Subversion Repositories HelenOS

Rev

Rev 2450 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 jermar 1
/*
2336 mencl 2
 * Copyright (C) 2001-2004 Jakub Jermar
2431 mencl 3
 * Copyright (C) 2007 Vojtech Mencl
1 jermar 4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 *
10
 * - Redistributions of source code must retain the above copyright
11
 *   notice, this list of conditions and the following disclaimer.
12
 * - Redistributions in binary form must reproduce the above copyright
13
 *   notice, this list of conditions and the following disclaimer in the
14
 *   documentation and/or other materials provided with the distribution.
15
 * - The name of the author may not be used to endorse or promote products
16
 *   derived from this software without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 */
29
 
1731 jermar 30
/** @addtogroup time
1702 cejka 31
 * @{
32
 */
33
 
1264 jermar 34
/**
1702 cejka 35
 * @file
1264 jermar 36
 * @brief   Timeout management functions.
37
 */
38
 
1 jermar 39
#include <time/timeout.h>
40
#include <arch/types.h>
41
#include <config.h>
68 decky 42
#include <panic.h>
1 jermar 43
#include <synch/spinlock.h>
44
#include <func.h>
45
#include <cpu.h>
46
#include <arch/asm.h>
47
#include <arch.h>
48
 
2336 mencl 49
 
107 decky 50
/** Initialize timeouts
51
 *
52
 * Initialize kernel timeouts.
53
 *
54
 */
1 jermar 55
void timeout_init(void)
56
{
552 palkovsky 57
    spinlock_initialize(&CPU->timeoutlock, "timeout_lock");
2336 mencl 58
 
2416 mencl 59
#if defined CONFIG_TIMEOUT_AVL_TREE
60
    avltree_create(&CPU->timeout_active_tree);
2461 mencl 61
#elif defined CONFIG_TIMEOUT_FAVL_TREE
62
    favltree_create(&CPU->timeout_active_tree);
2416 mencl 63
#elif defined CONFIG_TIMEOUT_EXTAVL_TREE
2336 mencl 64
    extavltree_create(&CPU->timeout_active_tree);
2421 mencl 65
#elif defined CONFIG_TIMEOUT_EXTAVLREL_TREE
2416 mencl 66
    extavlreltree_create(&CPU->timeout_active_tree);
2336 mencl 67
#else
15 jermar 68
    list_initialize(&CPU->timeout_active_head);
2336 mencl 69
#endif
1 jermar 70
}
71
 
72
 
411 jermar 73
/** Reinitialize timeout
107 decky 74
 *
411 jermar 75
 * Initialize all members except the lock.
107 decky 76
 *
411 jermar 77
 * @param t Timeout to be initialized.
107 decky 78
 *
79
 */
1 jermar 80
void timeout_reinitialize(timeout_t *t)
81
{
82
    t->cpu = NULL;
83
    t->handler = NULL;
84
    t->arg = NULL;
2416 mencl 85
 
86
#if defined CONFIG_TIMEOUT_AVL_TREE
87
    avltree_node_initialize(&t->node);
2461 mencl 88
#elif defined CONFIG_TIMEOUT_FAVL_TREE
89
    favltree_node_initialize(&t->node);
2416 mencl 90
#elif defined CONFIG_TIMEOUT_EXTAVL_TREE
2336 mencl 91
    extavltree_node_initialize(&t->node);
2416 mencl 92
#elif defined CONFIG_TIMEOUT_EXTAVLREL_TREE
93
    extavlreltree_node_initialize(&t->node);
2336 mencl 94
#else
95
    t->ticks = 0;
1 jermar 96
    link_initialize(&t->link);
2336 mencl 97
#endif
1 jermar 98
}
99
 
107 decky 100
 
411 jermar 101
/** Initialize timeout
107 decky 102
 *
411 jermar 103
 * Initialize all members including the lock.
107 decky 104
 *
411 jermar 105
 * @param t Timeout to be initialized.
107 decky 106
 *
107
 */
1 jermar 108
void timeout_initialize(timeout_t *t)
109
{
552 palkovsky 110
    spinlock_initialize(&t->lock, "timeout_t_lock");
1 jermar 111
    timeout_reinitialize(t);
112
}
113
 
2416 mencl 114
#if defined CONFIG_TIMEOUT_AVL_TREE || \
2461 mencl 115
    defined CONFIG_TIMEOUT_FAVL_TREE || \
2416 mencl 116
    defined CONFIG_TIMEOUT_EXTAVL_TREE || \
117
    defined CONFIG_TIMEOUT_EXTAVLREL_TREE
118
 
2336 mencl 119
/** Register timeout
120
 *
121
 * Insert timeout handler f (with argument arg)
2461 mencl 122
 * to timeout tree and make it execute in
2336 mencl 123
 * time microseconds (or slightly more).
124
 *
125
 * @param t    Timeout structure.
126
 * @param time Number of usec in the future to execute
127
 *             the handler.
128
 * @param f    Timeout handler function.
129
 * @param arg  Timeout handler argument.
130
 *
131
 */
132
void timeout_register(timeout_t *t, uint64_t time, timeout_handler_t f, void *arg)
133
{
134
    ipl_t ipl;
107 decky 135
 
2336 mencl 136
    ipl = interrupts_disable();
137
    spinlock_lock(&CPU->timeoutlock);
138
    spinlock_lock(&t->lock);
139
 
140
    if (t->cpu)
141
        panic("t->cpu != 0");
142
 
143
    t->cpu = CPU;
144
    t->handler = f;
145
    t->arg = arg;
2416 mencl 146
    t->node.key = us2ticks(time);
2336 mencl 147
 
2416 mencl 148
    /*
2461 mencl 149
     * Insert timeout into tree structure.
2416 mencl 150
     */
151
#if defined CONFIG_TIMEOUT_AVL_TREE
152
    avltree_insert(&CPU->timeout_active_tree,&t->node);
2461 mencl 153
#elif defined CONFIG_TIMEOUT_FAVL_TREE
154
    favltree_insert(&CPU->timeout_active_tree,&t->node);
2416 mencl 155
#elif defined CONFIG_TIMEOUT_EXTAVL_TREE
2336 mencl 156
    extavltree_insert(&CPU->timeout_active_tree,&t->node);
2416 mencl 157
#elif defined CONFIG_TIMEOUT_EXTAVLREL_TREE
158
    extavlreltree_insert(&CPU->timeout_active_tree,&t->node);
159
#endif
160
 
2336 mencl 161
    spinlock_unlock(&t->lock);
162
    spinlock_unlock(&CPU->timeoutlock);
163
    interrupts_restore(ipl);
164
}
165
 
166
 
167
/** Unregister timeout
168
 *
2461 mencl 169
 * Remove timeout from timeout tree structure.
2336 mencl 170
 *
171
 * @param t Timeout to unregister.
172
 *
173
 * @return true on success, false on failure.
174
 */
175
bool timeout_unregister(timeout_t *t)
176
{
177
    ipl_t ipl;
178
 
179
grab_locks:
180
    ipl = interrupts_disable();
181
    spinlock_lock(&t->lock);
182
    if (!t->cpu) {
183
        spinlock_unlock(&t->lock);
184
        interrupts_restore(ipl);
185
        return false;
186
    }
187
    if (!spinlock_trylock(&t->cpu->timeoutlock)) {
188
        spinlock_unlock(&t->lock);
189
        interrupts_restore(ipl);       
190
        goto grab_locks;
191
    }
192
    /*
193
     * Now we know for sure that t hasn't been activated yet
194
     * and is lurking in t->cpu->timeout_active_head queue.
195
     */
196
 
2416 mencl 197
    /*
198
     * Delete timeout from tree structure.
199
     */
200
#if defined CONFIG_TIMEOUT_AVL_TREE
2450 mencl 201
    avltree_delete(&t->cpu->timeout_active_tree,&t->node);
2461 mencl 202
#elif defined CONFIG_TIMEOUT_FAVL_TREE
203
    favltree_delete(&t->cpu->timeout_active_tree,&t->node);
2416 mencl 204
#elif defined CONFIG_TIMEOUT_EXTAVL_TREE
2450 mencl 205
    extavltree_delete(&t->cpu->timeout_active_tree,&t->node);
2416 mencl 206
#elif defined CONFIG_TIMEOUT_EXTAVLREL_TREE
2450 mencl 207
    extavlreltree_delete(&t->cpu->timeout_active_tree,&t->node);
2416 mencl 208
#endif
209
 
2336 mencl 210
    spinlock_unlock(&t->cpu->timeoutlock);
211
 
212
    timeout_reinitialize(t);
213
    spinlock_unlock(&t->lock);
214
 
215
    interrupts_restore(ipl);
216
    return true;
217
}
218
 
219
#else
220
 
411 jermar 221
/** Register timeout
107 decky 222
 *
411 jermar 223
 * Insert timeout handler f (with argument arg)
224
 * to timeout list and make it execute in
107 decky 225
 * time microseconds (or slightly more).
226
 *
411 jermar 227
 * @param t    Timeout structure.
404 jermar 228
 * @param time Number of usec in the future to execute
107 decky 229
 *             the handler.
230
 * @param f    Timeout handler function.
231
 * @param arg  Timeout handler argument.
232
 *
1 jermar 233
 */
1780 jermar 234
void timeout_register(timeout_t *t, uint64_t time, timeout_handler_t f, void *arg)
1 jermar 235
{
659 jermar 236
    timeout_t *hlp = NULL;
1 jermar 237
    link_t *l, *m;
413 jermar 238
    ipl_t ipl;
1780 jermar 239
    uint64_t sum;
1 jermar 240
 
413 jermar 241
    ipl = interrupts_disable();
15 jermar 242
    spinlock_lock(&CPU->timeoutlock);
1 jermar 243
    spinlock_lock(&t->lock);
125 jermar 244
 
1 jermar 245
    if (t->cpu)
103 jermar 246
        panic("t->cpu != 0");
1 jermar 247
 
15 jermar 248
    t->cpu = CPU;
1 jermar 249
    t->ticks = us2ticks(time);
250
 
251
    t->handler = f;
252
    t->arg = arg;
125 jermar 253
 
1 jermar 254
    /*
255
     * Insert t into the active timeouts list according to t->ticks.
256
     */
257
    sum = 0;
15 jermar 258
    l = CPU->timeout_active_head.next;
259
    while (l != &CPU->timeout_active_head) {
1 jermar 260
        hlp = list_get_instance(l, timeout_t, link);
261
        spinlock_lock(&hlp->lock);
262
        if (t->ticks < sum + hlp->ticks) {
263
            spinlock_unlock(&hlp->lock);
264
            break;
265
        }
266
        sum += hlp->ticks;
267
        spinlock_unlock(&hlp->lock);
268
        l = l->next;
269
    }
239 vana 270
 
1 jermar 271
    m = l->prev;
272
    list_prepend(&t->link, m); /* avoid using l->prev */
273
 
274
    /*
275
     * Adjust t->ticks according to ticks accumulated in h's predecessors.
276
     */
277
    t->ticks -= sum;
278
 
279
    /*
280
     * Decrease ticks of t's immediate succesor by t->ticks.
281
     */
15 jermar 282
    if (l != &CPU->timeout_active_head) {
1 jermar 283
        spinlock_lock(&hlp->lock);
284
        hlp->ticks -= t->ticks;
285
        spinlock_unlock(&hlp->lock);
286
    }
287
 
288
    spinlock_unlock(&t->lock);
15 jermar 289
    spinlock_unlock(&CPU->timeoutlock);
413 jermar 290
    interrupts_restore(ipl);
1 jermar 291
}
292
 
107 decky 293
 
411 jermar 294
/** Unregister timeout
107 decky 295
 *
296
 * Remove timeout from timeout list.
297
 *
298
 * @param t Timeout to unregister.
299
 *
411 jermar 300
 * @return true on success, false on failure.
107 decky 301
 */
411 jermar 302
bool timeout_unregister(timeout_t *t)
1 jermar 303
{
304
    timeout_t *hlp;
305
    link_t *l;
413 jermar 306
    ipl_t ipl;
1 jermar 307
 
308
grab_locks:
413 jermar 309
    ipl = interrupts_disable();
1 jermar 310
    spinlock_lock(&t->lock);
311
    if (!t->cpu) {
312
        spinlock_unlock(&t->lock);
413 jermar 313
        interrupts_restore(ipl);
411 jermar 314
        return false;
1 jermar 315
    }
316
    if (!spinlock_trylock(&t->cpu->timeoutlock)) {
317
        spinlock_unlock(&t->lock);
2336 mencl 318
        interrupts_restore(ipl);       
1 jermar 319
        goto grab_locks;
320
    }
321
 
322
    /*
323
     * Now we know for sure that t hasn't been activated yet
324
     * and is lurking in t->cpu->timeout_active_head queue.
325
     */
326
 
327
    l = t->link.next;
328
    if (l != &t->cpu->timeout_active_head) {
329
        hlp = list_get_instance(l, timeout_t, link);
330
        spinlock_lock(&hlp->lock);
331
        hlp->ticks += t->ticks;
332
        spinlock_unlock(&hlp->lock);
333
    }
334
 
335
    list_remove(&t->link);
336
    spinlock_unlock(&t->cpu->timeoutlock);
337
 
338
    timeout_reinitialize(t);
339
    spinlock_unlock(&t->lock);
340
 
413 jermar 341
    interrupts_restore(ipl);
411 jermar 342
    return true;
1 jermar 343
}
1702 cejka 344
 
2336 mencl 345
#endif
1731 jermar 346
/** @}
1702 cejka 347
 */