TCP: Fixed RTO update and dup ACKs generation.
[haiku.git] / src / libs / compat / freebsd_network / callout.cpp
blobc80938b63e5c8048e7a6bf0583ee5d9b229b0fc5
1 /*
2 * Copyright 2010, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "device.h"
9 #include <lock.h>
10 #include <thread.h>
12 extern "C" {
13 # include <sys/callout.h>
14 # include <sys/mutex.h>
17 #include <util/AutoLock.h>
20 //#define TRACE_CALLOUT
21 #ifdef TRACE_CALLOUT
22 # define TRACE(x...) dprintf(x)
23 #else
24 # define TRACE(x...) ;
25 #endif
28 static struct list sTimers;
29 static mutex sLock;
30 static sem_id sWaitSem;
31 static callout* sCurrentCallout;
32 static thread_id sThread;
33 static bigtime_t sTimeout;
36 static status_t
37 callout_thread(void* /*data*/)
39 status_t status = B_OK;
41 do {
42 bigtime_t timeout = B_INFINITE_TIMEOUT;
44 if (status == B_TIMED_OUT || status == B_OK) {
45 // scan timers for new timeout and/or execute a timer
46 mutex_lock(&sLock);
48 struct callout* c = NULL;
49 while (true) {
50 c = (callout*)list_get_next_item(&sTimers, c);
51 if (c == NULL)
52 break;
54 if (c->due < system_time()) {
55 struct mtx *mutex = c->c_mtx;
57 // execute timer
58 list_remove_item(&sTimers, c);
59 c->due = -1;
60 sCurrentCallout = c;
62 mutex_unlock(&sLock);
64 if (mutex != NULL)
65 mtx_lock(mutex);
67 c->c_func(c->c_arg);
69 if (mutex != NULL)
70 mtx_unlock(mutex);
72 mutex_lock(&sLock);
74 sCurrentCallout = NULL;
75 c = NULL;
76 // restart scanning as we unlocked the list
77 } else {
78 // calculate new timeout
79 if (c->due < timeout)
80 timeout = c->due;
84 sTimeout = timeout;
85 mutex_unlock(&sLock);
88 status = acquire_sem_etc(sWaitSem, 1, B_ABSOLUTE_TIMEOUT, timeout);
89 // the wait sem normally can't be acquired, so we
90 // have to look at the status value the call returns:
92 // B_OK - a new timer has been added or canceled
93 // B_TIMED_OUT - look for timers to be executed
94 // B_BAD_SEM_ID - we are asked to quit
95 } while (status != B_BAD_SEM_ID);
97 return B_OK;
101 // #pragma mark - private API
104 status_t
105 init_callout(void)
107 list_init(&sTimers);
108 sTimeout = B_INFINITE_TIMEOUT;
110 status_t status = B_OK;
111 mutex_init(&sLock, "fbsd callout");
113 sWaitSem = create_sem(0, "fbsd callout wait");
114 if (sWaitSem < 0) {
115 status = sWaitSem;
116 goto err1;
119 sThread = spawn_kernel_thread(callout_thread, "fbsd callout",
120 B_DISPLAY_PRIORITY, NULL);
121 if (sThread < 0) {
122 status = sThread;
123 goto err2;
126 return resume_thread(sThread);
128 err1:
129 mutex_destroy(&sLock);
130 err2:
131 delete_sem(sWaitSem);
132 return status;
136 void
137 uninit_callout(void)
139 delete_sem(sWaitSem);
140 mutex_lock(&sLock);
142 mutex_destroy(&sLock);
144 status_t status;
145 wait_for_thread(sThread, &status);
149 // #pragma mark - public API
152 void
153 callout_init(struct callout *callout, int mpsafe)
155 if (mpsafe)
156 callout_init_mtx(callout, NULL, 0);
157 else
158 callout_init_mtx(callout, &Giant, 0);
162 void
163 callout_init_mtx(struct callout *c, struct mtx *mtx, int flags)
165 c->due = 0;
166 c->flags = 0;
168 c->c_arg = NULL;
169 c->c_func = NULL;
170 c->c_mtx = mtx;
171 c->c_flags = flags;
176 callout_reset(struct callout *c, int ticks, void (*func)(void *), void *arg)
178 int canceled = callout_stop(c);
180 MutexLocker locker(sLock);
182 c->c_func = func;
183 c->c_arg = arg;
185 TRACE("callout_reset %p, func %p, arg %p\n", c, c->c_func, c->c_arg);
187 if (ticks >= 0) {
188 // reschedule or add this timer
189 if (c->due <= 0)
190 list_add_item(&sTimers, c);
192 c->due = system_time() + ticks_to_usecs(ticks);
194 // notify timer about the change if necessary
195 if (sTimeout > c->due)
196 release_sem(sWaitSem);
199 return canceled;
204 callout_schedule(struct callout *callout, int ticks)
206 return callout_reset(callout, ticks, callout->c_func, callout->c_arg);
211 _callout_stop_safe(struct callout *c, int safe)
213 MutexLocker locker(sLock);
215 TRACE("_callout_stop_safe %p, func %p, arg %p\n", c, c->c_func, c->c_arg);
217 if (c->due <= 0)
218 return 0;
220 // this timer is scheduled, cancel it
221 list_remove_item(&sTimers, c);
222 c->due = 0;
223 return 1;
228 callout_pending(struct callout *c)
230 return c->due > 0;
235 callout_active(struct callout *c)
237 return c == sCurrentCallout;