ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / net / rxrpc / krxtimod.c
1 /* krxtimod.c: RXRPC timeout 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/module.h>
13 #include <linux/init.h>
14 #include <linux/sched.h>
15 #include <linux/completion.h>
16 #include <rxrpc/rxrpc.h>
17 #include <rxrpc/krxtimod.h>
18 #include <asm/errno.h>
19 #include "internal.h"
20
21 static DECLARE_COMPLETION(krxtimod_alive);
22 static DECLARE_COMPLETION(krxtimod_dead);
23 static DECLARE_WAIT_QUEUE_HEAD(krxtimod_sleepq);
24 static int krxtimod_die;
25
26 static LIST_HEAD(krxtimod_list);
27 static spinlock_t krxtimod_lock = SPIN_LOCK_UNLOCKED;
28
29 static int krxtimod(void *arg);
30
31 /*****************************************************************************/
32 /*
33  * start the timeout daemon
34  */
35 int rxrpc_krxtimod_start(void)
36 {
37         int ret;
38
39         ret = kernel_thread(krxtimod, NULL, 0);
40         if (ret < 0)
41                 return ret;
42
43         wait_for_completion(&krxtimod_alive);
44
45         return ret;
46 } /* end rxrpc_krxtimod_start() */
47
48 /*****************************************************************************/
49 /*
50  * stop the timeout daemon
51  */
52 void rxrpc_krxtimod_kill(void)
53 {
54         /* get rid of my daemon */
55         krxtimod_die = 1;
56         wake_up(&krxtimod_sleepq);
57         wait_for_completion(&krxtimod_dead);
58
59 } /* end rxrpc_krxtimod_kill() */
60
61 /*****************************************************************************/
62 /*
63  * timeout processing daemon
64  */
65 static int krxtimod(void *arg)
66 {
67         DECLARE_WAITQUEUE(myself, current);
68
69         rxrpc_timer_t *timer;
70
71         printk("Started krxtimod %d\n", current->pid);
72
73         daemonize("krxtimod");
74
75         complete(&krxtimod_alive);
76
77         /* loop around looking for things to attend to */
78  loop:
79         set_current_state(TASK_INTERRUPTIBLE);
80         add_wait_queue(&krxtimod_sleepq, &myself);
81
82         for (;;) {
83                 unsigned long jif;
84                 signed long timeout;
85
86                 /* deal with the server being asked to die */
87                 if (krxtimod_die) {
88                         remove_wait_queue(&krxtimod_sleepq, &myself);
89                         _leave("");
90                         complete_and_exit(&krxtimod_dead, 0);
91                 }
92
93                 /* discard pending signals */
94                 rxrpc_discard_my_signals();
95
96                 /* work out the time to elapse before the next event */
97                 spin_lock(&krxtimod_lock);
98                 if (list_empty(&krxtimod_list)) {
99                         timeout = MAX_SCHEDULE_TIMEOUT;
100                 }
101                 else {
102                         timer = list_entry(krxtimod_list.next,
103                                            rxrpc_timer_t, link);
104                         timeout = timer->timo_jif;
105                         jif = jiffies;
106
107                         if (time_before_eq((unsigned long) timeout, jif))
108                                 goto immediate;
109
110                         else {
111                                 timeout = (long) timeout - (long) jiffies;
112                         }
113                 }
114                 spin_unlock(&krxtimod_lock);
115
116                 schedule_timeout(timeout);
117
118                 set_current_state(TASK_INTERRUPTIBLE);
119         }
120
121         /* the thing on the front of the queue needs processing
122          * - we come here with the lock held and timer pointing to the expired
123          *   entry
124          */
125  immediate:
126         remove_wait_queue(&krxtimod_sleepq, &myself);
127         set_current_state(TASK_RUNNING);
128
129         _debug("@@@ Begin Timeout of %p", timer);
130
131         /* dequeue the timer */
132         list_del_init(&timer->link);
133         spin_unlock(&krxtimod_lock);
134
135         /* call the timeout function */
136         timer->ops->timed_out(timer);
137
138         _debug("@@@ End Timeout");
139         goto loop;
140
141 } /* end krxtimod() */
142
143 /*****************************************************************************/
144 /*
145  * (re-)queue a timer
146  */
147 void rxrpc_krxtimod_add_timer(rxrpc_timer_t *timer, unsigned long timeout)
148 {
149         struct list_head *_p;
150         rxrpc_timer_t *ptimer;
151
152         _enter("%p,%lu", timer, timeout);
153
154         spin_lock(&krxtimod_lock);
155
156         list_del(&timer->link);
157
158         /* the timer was deferred or reset - put it back in the queue at the
159          * right place */
160         timer->timo_jif = jiffies + timeout;
161
162         list_for_each(_p, &krxtimod_list) {
163                 ptimer = list_entry(_p, rxrpc_timer_t, link);
164                 if (time_before(timer->timo_jif, ptimer->timo_jif))
165                         break;
166         }
167
168         list_add_tail(&timer->link, _p); /* insert before stopping point */
169
170         spin_unlock(&krxtimod_lock);
171
172         wake_up(&krxtimod_sleepq);
173
174         _leave("");
175 } /* end rxrpc_krxtimod_add_timer() */
176
177 /*****************************************************************************/
178 /*
179  * dequeue a timer
180  * - returns 0 if the timer was deleted or -ENOENT if it wasn't queued
181  */
182 int rxrpc_krxtimod_del_timer(rxrpc_timer_t *timer)
183 {
184         int ret = 0;
185
186         _enter("%p", timer);
187
188         spin_lock(&krxtimod_lock);
189
190         if (list_empty(&timer->link))
191                 ret = -ENOENT;
192         else
193                 list_del_init(&timer->link);
194
195         spin_unlock(&krxtimod_lock);
196
197         wake_up(&krxtimod_sleepq);
198
199         _leave(" = %d", ret);
200         return ret;
201 } /* end rxrpc_krxtimod_del_timer() */