blob: 249c2b0290bbfeae3bedccecf82af87301769b7f [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>
16#include <rxrpc/rxrpc.h>
17#include <rxrpc/krxtimod.h>
18#include <asm/errno.h>
19#include "internal.h"
20
21static DECLARE_COMPLETION(krxtimod_alive);
22static DECLARE_COMPLETION(krxtimod_dead);
23static DECLARE_WAIT_QUEUE_HEAD(krxtimod_sleepq);
24static int krxtimod_die;
25
26static LIST_HEAD(krxtimod_list);
27static DEFINE_SPINLOCK(krxtimod_lock);
28
29static int krxtimod(void *arg);
30
31/*****************************************************************************/
32/*
33 * start the timeout daemon
34 */
35int 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 */
52void 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 */
65static 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 try_to_freeze(PF_FREEZE);
94
95 /* discard pending signals */
96 rxrpc_discard_my_signals();
97
98 /* work out the time to elapse before the next event */
99 spin_lock(&krxtimod_lock);
100 if (list_empty(&krxtimod_list)) {
101 timeout = MAX_SCHEDULE_TIMEOUT;
102 }
103 else {
104 timer = list_entry(krxtimod_list.next,
105 rxrpc_timer_t, link);
106 timeout = timer->timo_jif;
107 jif = jiffies;
108
109 if (time_before_eq((unsigned long) timeout, jif))
110 goto immediate;
111
112 else {
113 timeout = (long) timeout - (long) jiffies;
114 }
115 }
116 spin_unlock(&krxtimod_lock);
117
118 schedule_timeout(timeout);
119
120 set_current_state(TASK_INTERRUPTIBLE);
121 }
122
123 /* the thing on the front of the queue needs processing
124 * - we come here with the lock held and timer pointing to the expired
125 * entry
126 */
127 immediate:
128 remove_wait_queue(&krxtimod_sleepq, &myself);
129 set_current_state(TASK_RUNNING);
130
131 _debug("@@@ Begin Timeout of %p", timer);
132
133 /* dequeue the timer */
134 list_del_init(&timer->link);
135 spin_unlock(&krxtimod_lock);
136
137 /* call the timeout function */
138 timer->ops->timed_out(timer);
139
140 _debug("@@@ End Timeout");
141 goto loop;
142
143} /* end krxtimod() */
144
145/*****************************************************************************/
146/*
147 * (re-)queue a timer
148 */
149void rxrpc_krxtimod_add_timer(rxrpc_timer_t *timer, unsigned long timeout)
150{
151 struct list_head *_p;
152 rxrpc_timer_t *ptimer;
153
154 _enter("%p,%lu", timer, timeout);
155
156 spin_lock(&krxtimod_lock);
157
158 list_del(&timer->link);
159
160 /* the timer was deferred or reset - put it back in the queue at the
161 * right place */
162 timer->timo_jif = jiffies + timeout;
163
164 list_for_each(_p, &krxtimod_list) {
165 ptimer = list_entry(_p, rxrpc_timer_t, link);
166 if (time_before(timer->timo_jif, ptimer->timo_jif))
167 break;
168 }
169
170 list_add_tail(&timer->link, _p); /* insert before stopping point */
171
172 spin_unlock(&krxtimod_lock);
173
174 wake_up(&krxtimod_sleepq);
175
176 _leave("");
177} /* end rxrpc_krxtimod_add_timer() */
178
179/*****************************************************************************/
180/*
181 * dequeue a timer
182 * - returns 0 if the timer was deleted or -ENOENT if it wasn't queued
183 */
184int rxrpc_krxtimod_del_timer(rxrpc_timer_t *timer)
185{
186 int ret = 0;
187
188 _enter("%p", timer);
189
190 spin_lock(&krxtimod_lock);
191
192 if (list_empty(&timer->link))
193 ret = -ENOENT;
194 else
195 list_del_init(&timer->link);
196
197 spin_unlock(&krxtimod_lock);
198
199 wake_up(&krxtimod_sleepq);
200
201 _leave(" = %d", ret);
202 return ret;
203} /* end rxrpc_krxtimod_del_timer() */