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