1 /* kafstimod.c: AFS timeout daemon
3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/sched.h>
15 #include <linux/completion.h>
16 #include <linux/freezer.h>
19 #include "kafstimod.h"
20 #include <asm/errno.h>
23 static DECLARE_COMPLETION(kafstimod_alive
);
24 static DECLARE_COMPLETION(kafstimod_dead
);
25 static DECLARE_WAIT_QUEUE_HEAD(kafstimod_sleepq
);
26 static int kafstimod_die
;
28 static LIST_HEAD(kafstimod_list
);
29 static DEFINE_SPINLOCK(kafstimod_lock
);
31 static int kafstimod(void *arg
);
33 /*****************************************************************************/
35 * start the timeout daemon
37 int afs_kafstimod_start(void)
41 ret
= kernel_thread(kafstimod
, NULL
, 0);
45 wait_for_completion(&kafstimod_alive
);
48 } /* end afs_kafstimod_start() */
50 /*****************************************************************************/
52 * stop the timeout daemon
54 void afs_kafstimod_stop(void)
56 /* get rid of my daemon */
58 wake_up(&kafstimod_sleepq
);
59 wait_for_completion(&kafstimod_dead
);
61 } /* end afs_kafstimod_stop() */
63 /*****************************************************************************/
65 * timeout processing daemon
67 static int kafstimod(void *arg
)
69 struct afs_timer
*timer
;
71 DECLARE_WAITQUEUE(myself
, current
);
73 printk("kAFS: Started kafstimod %d\n", current
->pid
);
75 daemonize("kafstimod");
77 complete(&kafstimod_alive
);
79 /* loop around looking for things to attend to */
81 set_current_state(TASK_INTERRUPTIBLE
);
82 add_wait_queue(&kafstimod_sleepq
, &myself
);
88 /* deal with the server being asked to die */
90 remove_wait_queue(&kafstimod_sleepq
, &myself
);
92 complete_and_exit(&kafstimod_dead
, 0);
97 /* discard pending signals */
98 afs_discard_my_signals();
100 /* work out the time to elapse before the next event */
101 spin_lock(&kafstimod_lock
);
102 if (list_empty(&kafstimod_list
)) {
103 timeout
= MAX_SCHEDULE_TIMEOUT
;
106 timer
= list_entry(kafstimod_list
.next
,
107 struct afs_timer
, link
);
108 timeout
= timer
->timo_jif
;
111 if (time_before_eq((unsigned long) timeout
, jif
))
115 timeout
= (long) timeout
- (long) jiffies
;
118 spin_unlock(&kafstimod_lock
);
120 schedule_timeout(timeout
);
122 set_current_state(TASK_INTERRUPTIBLE
);
125 /* the thing on the front of the queue needs processing
126 * - we come here with the lock held and timer pointing to the expired
130 remove_wait_queue(&kafstimod_sleepq
, &myself
);
131 set_current_state(TASK_RUNNING
);
133 _debug("@@@ Begin Timeout of %p", timer
);
135 /* dequeue the timer */
136 list_del_init(&timer
->link
);
137 spin_unlock(&kafstimod_lock
);
139 /* call the timeout function */
140 timer
->ops
->timed_out(timer
);
142 _debug("@@@ End Timeout");
145 } /* end kafstimod() */
147 /*****************************************************************************/
151 void afs_kafstimod_add_timer(struct afs_timer
*timer
, unsigned long timeout
)
153 struct afs_timer
*ptimer
;
154 struct list_head
*_p
;
156 _enter("%p,%lu", timer
, timeout
);
158 spin_lock(&kafstimod_lock
);
160 list_del(&timer
->link
);
162 /* the timer was deferred or reset - put it back in the queue at the
164 timer
->timo_jif
= jiffies
+ timeout
;
166 list_for_each(_p
, &kafstimod_list
) {
167 ptimer
= list_entry(_p
, struct afs_timer
, link
);
168 if (time_before(timer
->timo_jif
, ptimer
->timo_jif
))
172 list_add_tail(&timer
->link
, _p
); /* insert before stopping point */
174 spin_unlock(&kafstimod_lock
);
176 wake_up(&kafstimod_sleepq
);
179 } /* end afs_kafstimod_add_timer() */
181 /*****************************************************************************/
184 * - returns 0 if the timer was deleted or -ENOENT if it wasn't queued
186 int afs_kafstimod_del_timer(struct afs_timer
*timer
)
192 spin_lock(&kafstimod_lock
);
194 if (list_empty(&timer
->link
))
197 list_del_init(&timer
->link
);
199 spin_unlock(&kafstimod_lock
);
201 wake_up(&kafstimod_sleepq
);
203 _leave(" = %d", ret
);
205 } /* end afs_kafstimod_del_timer() */