]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* krxiod.c: Rx I/O daemon |
2 | * | |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | |
4 | * Written by David Howells (dhowells@redhat.com) | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version | |
9 | * 2 of the License, or (at your option) any later version. | |
10 | */ | |
11 | ||
12 | #include <linux/sched.h> | |
13 | #include <linux/completion.h> | |
14 | #include <linux/spinlock.h> | |
15 | #include <linux/init.h> | |
7dfb7103 | 16 | #include <linux/freezer.h> |
1da177e4 LT |
17 | #include <rxrpc/krxiod.h> |
18 | #include <rxrpc/transport.h> | |
19 | #include <rxrpc/peer.h> | |
20 | #include <rxrpc/call.h> | |
21 | #include "internal.h" | |
22 | ||
23 | static DECLARE_WAIT_QUEUE_HEAD(rxrpc_krxiod_sleepq); | |
24 | static DECLARE_COMPLETION(rxrpc_krxiod_dead); | |
25 | ||
26 | static atomic_t rxrpc_krxiod_qcount = ATOMIC_INIT(0); | |
27 | ||
28 | static LIST_HEAD(rxrpc_krxiod_transportq); | |
29 | static DEFINE_SPINLOCK(rxrpc_krxiod_transportq_lock); | |
30 | ||
31 | static LIST_HEAD(rxrpc_krxiod_callq); | |
32 | static DEFINE_SPINLOCK(rxrpc_krxiod_callq_lock); | |
33 | ||
34 | static volatile int rxrpc_krxiod_die; | |
35 | ||
36 | /*****************************************************************************/ | |
37 | /* | |
38 | * Rx I/O daemon | |
39 | */ | |
40 | static int rxrpc_krxiod(void *arg) | |
41 | { | |
42 | DECLARE_WAITQUEUE(krxiod,current); | |
43 | ||
44 | printk("Started krxiod %d\n",current->pid); | |
45 | ||
46 | daemonize("krxiod"); | |
47 | ||
48 | /* loop around waiting for work to do */ | |
49 | do { | |
50 | /* wait for work or to be told to exit */ | |
51 | _debug("### Begin Wait"); | |
52 | if (!atomic_read(&rxrpc_krxiod_qcount)) { | |
53 | set_current_state(TASK_INTERRUPTIBLE); | |
54 | ||
55 | add_wait_queue(&rxrpc_krxiod_sleepq, &krxiod); | |
56 | ||
57 | for (;;) { | |
58 | set_current_state(TASK_INTERRUPTIBLE); | |
59 | if (atomic_read(&rxrpc_krxiod_qcount) || | |
60 | rxrpc_krxiod_die || | |
61 | signal_pending(current)) | |
62 | break; | |
63 | ||
64 | schedule(); | |
65 | } | |
66 | ||
67 | remove_wait_queue(&rxrpc_krxiod_sleepq, &krxiod); | |
68 | set_current_state(TASK_RUNNING); | |
69 | } | |
70 | _debug("### End Wait"); | |
71 | ||
72 | /* do work if been given some to do */ | |
73 | _debug("### Begin Work"); | |
74 | ||
75 | /* see if there's a transport in need of attention */ | |
76 | if (!list_empty(&rxrpc_krxiod_transportq)) { | |
77 | struct rxrpc_transport *trans = NULL; | |
78 | ||
79 | spin_lock_irq(&rxrpc_krxiod_transportq_lock); | |
80 | ||
81 | if (!list_empty(&rxrpc_krxiod_transportq)) { | |
82 | trans = list_entry( | |
83 | rxrpc_krxiod_transportq.next, | |
84 | struct rxrpc_transport, | |
85 | krxiodq_link); | |
86 | ||
87 | list_del_init(&trans->krxiodq_link); | |
88 | atomic_dec(&rxrpc_krxiod_qcount); | |
89 | ||
90 | /* make sure it hasn't gone away and doesn't go | |
91 | * away */ | |
92 | if (atomic_read(&trans->usage)>0) | |
93 | rxrpc_get_transport(trans); | |
94 | else | |
95 | trans = NULL; | |
96 | } | |
97 | ||
98 | spin_unlock_irq(&rxrpc_krxiod_transportq_lock); | |
99 | ||
100 | if (trans) { | |
101 | rxrpc_trans_receive_packet(trans); | |
102 | rxrpc_put_transport(trans); | |
103 | } | |
104 | } | |
105 | ||
106 | /* see if there's a call in need of attention */ | |
107 | if (!list_empty(&rxrpc_krxiod_callq)) { | |
108 | struct rxrpc_call *call = NULL; | |
109 | ||
110 | spin_lock_irq(&rxrpc_krxiod_callq_lock); | |
111 | ||
112 | if (!list_empty(&rxrpc_krxiod_callq)) { | |
113 | call = list_entry(rxrpc_krxiod_callq.next, | |
114 | struct rxrpc_call, | |
115 | rcv_krxiodq_lk); | |
116 | list_del_init(&call->rcv_krxiodq_lk); | |
117 | atomic_dec(&rxrpc_krxiod_qcount); | |
118 | ||
119 | /* make sure it hasn't gone away and doesn't go | |
120 | * away */ | |
121 | if (atomic_read(&call->usage) > 0) { | |
122 | _debug("@@@ KRXIOD" | |
123 | " Begin Attend Call %p", call); | |
124 | rxrpc_get_call(call); | |
125 | } | |
126 | else { | |
127 | call = NULL; | |
128 | } | |
129 | } | |
130 | ||
131 | spin_unlock_irq(&rxrpc_krxiod_callq_lock); | |
132 | ||
133 | if (call) { | |
134 | rxrpc_call_do_stuff(call); | |
135 | rxrpc_put_call(call); | |
136 | _debug("@@@ KRXIOD End Attend Call %p", call); | |
137 | } | |
138 | } | |
139 | ||
140 | _debug("### End Work"); | |
141 | ||
3e1d1d28 | 142 | try_to_freeze(); |
1da177e4 LT |
143 | |
144 | /* discard pending signals */ | |
145 | rxrpc_discard_my_signals(); | |
146 | ||
147 | } while (!rxrpc_krxiod_die); | |
148 | ||
149 | /* and that's all */ | |
150 | complete_and_exit(&rxrpc_krxiod_dead, 0); | |
151 | ||
152 | } /* end rxrpc_krxiod() */ | |
153 | ||
154 | /*****************************************************************************/ | |
155 | /* | |
156 | * start up a krxiod daemon | |
157 | */ | |
158 | int __init rxrpc_krxiod_init(void) | |
159 | { | |
160 | return kernel_thread(rxrpc_krxiod, NULL, 0); | |
161 | ||
162 | } /* end rxrpc_krxiod_init() */ | |
163 | ||
164 | /*****************************************************************************/ | |
165 | /* | |
166 | * kill the krxiod daemon and wait for it to complete | |
167 | */ | |
168 | void rxrpc_krxiod_kill(void) | |
169 | { | |
170 | rxrpc_krxiod_die = 1; | |
171 | wake_up_all(&rxrpc_krxiod_sleepq); | |
172 | wait_for_completion(&rxrpc_krxiod_dead); | |
173 | ||
174 | } /* end rxrpc_krxiod_kill() */ | |
175 | ||
176 | /*****************************************************************************/ | |
177 | /* | |
178 | * queue a transport for attention by krxiod | |
179 | */ | |
180 | void rxrpc_krxiod_queue_transport(struct rxrpc_transport *trans) | |
181 | { | |
182 | unsigned long flags; | |
183 | ||
184 | _enter(""); | |
185 | ||
186 | if (list_empty(&trans->krxiodq_link)) { | |
187 | spin_lock_irqsave(&rxrpc_krxiod_transportq_lock, flags); | |
188 | ||
189 | if (list_empty(&trans->krxiodq_link)) { | |
190 | if (atomic_read(&trans->usage) > 0) { | |
191 | list_add_tail(&trans->krxiodq_link, | |
192 | &rxrpc_krxiod_transportq); | |
193 | atomic_inc(&rxrpc_krxiod_qcount); | |
194 | } | |
195 | } | |
196 | ||
197 | spin_unlock_irqrestore(&rxrpc_krxiod_transportq_lock, flags); | |
198 | wake_up_all(&rxrpc_krxiod_sleepq); | |
199 | } | |
200 | ||
201 | _leave(""); | |
202 | ||
203 | } /* end rxrpc_krxiod_queue_transport() */ | |
204 | ||
205 | /*****************************************************************************/ | |
206 | /* | |
207 | * dequeue a transport from krxiod's attention queue | |
208 | */ | |
209 | void rxrpc_krxiod_dequeue_transport(struct rxrpc_transport *trans) | |
210 | { | |
211 | unsigned long flags; | |
212 | ||
213 | _enter(""); | |
214 | ||
215 | spin_lock_irqsave(&rxrpc_krxiod_transportq_lock, flags); | |
216 | if (!list_empty(&trans->krxiodq_link)) { | |
217 | list_del_init(&trans->krxiodq_link); | |
218 | atomic_dec(&rxrpc_krxiod_qcount); | |
219 | } | |
220 | spin_unlock_irqrestore(&rxrpc_krxiod_transportq_lock, flags); | |
221 | ||
222 | _leave(""); | |
223 | ||
224 | } /* end rxrpc_krxiod_dequeue_transport() */ | |
225 | ||
226 | /*****************************************************************************/ | |
227 | /* | |
228 | * queue a call for attention by krxiod | |
229 | */ | |
230 | void rxrpc_krxiod_queue_call(struct rxrpc_call *call) | |
231 | { | |
232 | unsigned long flags; | |
233 | ||
234 | if (list_empty(&call->rcv_krxiodq_lk)) { | |
235 | spin_lock_irqsave(&rxrpc_krxiod_callq_lock, flags); | |
236 | if (atomic_read(&call->usage) > 0) { | |
237 | list_add_tail(&call->rcv_krxiodq_lk, | |
238 | &rxrpc_krxiod_callq); | |
239 | atomic_inc(&rxrpc_krxiod_qcount); | |
240 | } | |
241 | spin_unlock_irqrestore(&rxrpc_krxiod_callq_lock, flags); | |
242 | } | |
243 | wake_up_all(&rxrpc_krxiod_sleepq); | |
244 | ||
245 | } /* end rxrpc_krxiod_queue_call() */ | |
246 | ||
247 | /*****************************************************************************/ | |
248 | /* | |
249 | * dequeue a call from krxiod's attention queue | |
250 | */ | |
251 | void rxrpc_krxiod_dequeue_call(struct rxrpc_call *call) | |
252 | { | |
253 | unsigned long flags; | |
254 | ||
255 | spin_lock_irqsave(&rxrpc_krxiod_callq_lock, flags); | |
256 | if (!list_empty(&call->rcv_krxiodq_lk)) { | |
257 | list_del_init(&call->rcv_krxiodq_lk); | |
258 | atomic_dec(&rxrpc_krxiod_qcount); | |
259 | } | |
260 | spin_unlock_irqrestore(&rxrpc_krxiod_callq_lock, flags); | |
261 | ||
262 | } /* end rxrpc_krxiod_dequeue_call() */ |