Subversion Repositories HelenOS

Rev

Rev 2421 | Rev 2450 | Go to most recent revision | 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);
61
#elif defined CONFIG_TIMEOUT_EXTAVL_TREE
2336 mencl 62
    extavltree_create(&CPU->timeout_active_tree);
2421 mencl 63
#elif defined CONFIG_TIMEOUT_EXTAVLREL_TREE
2416 mencl 64
    extavlreltree_create(&CPU->timeout_active_tree);
2336 mencl 65
#else
15 jermar 66
    list_initialize(&CPU->timeout_active_head);
2336 mencl 67
#endif
1 jermar 68
}
69
 
70
 
411 jermar 71
/** Reinitialize timeout
107 decky 72
 *
411 jermar 73
 * Initialize all members except the lock.
107 decky 74
 *
411 jermar 75
 * @param t Timeout to be initialized.
107 decky 76
 *
77
 */
1 jermar 78
void timeout_reinitialize(timeout_t *t)
79
{
80
    t->cpu = NULL;
81
    t->handler = NULL;
82
    t->arg = NULL;
2416 mencl 83
 
84
#if defined CONFIG_TIMEOUT_AVL_TREE
85
    avltree_node_initialize(&t->node);
86
#elif defined CONFIG_TIMEOUT_EXTAVL_TREE
2336 mencl 87
    extavltree_node_initialize(&t->node);
2416 mencl 88
#elif defined CONFIG_TIMEOUT_EXTAVLREL_TREE
89
    extavlreltree_node_initialize(&t->node);
2336 mencl 90
#else
91
    t->ticks = 0;
1 jermar 92
    link_initialize(&t->link);
2336 mencl 93
#endif
1 jermar 94
}
95
 
107 decky 96
 
411 jermar 97
/** Initialize timeout
107 decky 98
 *
411 jermar 99
 * Initialize all members including the lock.
107 decky 100
 *
411 jermar 101
 * @param t Timeout to be initialized.
107 decky 102
 *
103
 */
1 jermar 104
void timeout_initialize(timeout_t *t)
105
{
552 palkovsky 106
    spinlock_initialize(&t->lock, "timeout_t_lock");
1 jermar 107
    timeout_reinitialize(t);
108
}
109
 
2416 mencl 110
#if defined CONFIG_TIMEOUT_AVL_TREE || \
111
    defined CONFIG_TIMEOUT_EXTAVL_TREE || \
112
    defined CONFIG_TIMEOUT_EXTAVLREL_TREE
113
 
2336 mencl 114
/** Register timeout
115
 *
116
 * Insert timeout handler f (with argument arg)
2416 mencl 117
 * to timeout ExtAVL tree and make it execute in
2336 mencl 118
 * time microseconds (or slightly more).
119
 *
120
 * @param t    Timeout structure.
121
 * @param time Number of usec in the future to execute
122
 *             the handler.
123
 * @param f    Timeout handler function.
124
 * @param arg  Timeout handler argument.
125
 *
126
 */
127
void timeout_register(timeout_t *t, uint64_t time, timeout_handler_t f, void *arg)
128
{
129
    ipl_t ipl;
107 decky 130
 
2336 mencl 131
    ipl = interrupts_disable();
132
    spinlock_lock(&CPU->timeoutlock);
133
    spinlock_lock(&t->lock);
134
 
135
    if (t->cpu)
136
        panic("t->cpu != 0");
137
 
138
    t->cpu = CPU;
139
    t->handler = f;
140
    t->arg = arg;
2416 mencl 141
    t->node.key = us2ticks(time);
2336 mencl 142
 
2416 mencl 143
    /*
144
     * Put timeout into tree structure.
145
     */
146
#if defined CONFIG_TIMEOUT_AVL_TREE
147
    avltree_insert(&CPU->timeout_active_tree,&t->node);
148
#elif defined CONFIG_TIMEOUT_EXTAVL_TREE
2336 mencl 149
    extavltree_insert(&CPU->timeout_active_tree,&t->node);
2416 mencl 150
#elif defined CONFIG_TIMEOUT_EXTAVLREL_TREE
151
    extavlreltree_insert(&CPU->timeout_active_tree,&t->node);
152
#endif
153
 
2336 mencl 154
    spinlock_unlock(&t->lock);
155
    spinlock_unlock(&CPU->timeoutlock);
156
    interrupts_restore(ipl);
157
}
158
 
159
 
160
/** Unregister timeout
161
 *
2416 mencl 162
 * Remove timeout from timeout ExtAVL tree structure.
2336 mencl 163
 *
164
 * @param t Timeout to unregister.
165
 *
166
 * @return true on success, false on failure.
167
 */
168
bool timeout_unregister(timeout_t *t)
169
{
170
    ipl_t ipl;
171
 
172
grab_locks:
173
    ipl = interrupts_disable();
174
    spinlock_lock(&t->lock);
175
    if (!t->cpu) {
176
        spinlock_unlock(&t->lock);
177
        interrupts_restore(ipl);
178
        return false;
179
    }
180
    if (!spinlock_trylock(&t->cpu->timeoutlock)) {
181
        spinlock_unlock(&t->lock);
182
        interrupts_restore(ipl);       
183
        goto grab_locks;
184
    }
185
    /*
186
     * Now we know for sure that t hasn't been activated yet
187
     * and is lurking in t->cpu->timeout_active_head queue.
188
     */
189
 
2416 mencl 190
    /*
191
     * Delete timeout from tree structure.
192
     */
193
#if defined CONFIG_TIMEOUT_AVL_TREE
194
    avltree_delete(&CPU->timeout_active_tree,&t->node);
195
#elif defined CONFIG_TIMEOUT_EXTAVL_TREE
2336 mencl 196
    extavltree_delete(&CPU->timeout_active_tree,&t->node);
2416 mencl 197
#elif defined CONFIG_TIMEOUT_EXTAVLREL_TREE
198
    extavlreltree_delete(&CPU->timeout_active_tree,&t->node);
199
#endif
200
 
2336 mencl 201
    spinlock_unlock(&t->cpu->timeoutlock);
202
 
203
    timeout_reinitialize(t);
204
    spinlock_unlock(&t->lock);
205
 
206
    interrupts_restore(ipl);
207
    return true;
208
}
209
 
210
#else
211
 
411 jermar 212
/** Register timeout
107 decky 213
 *
411 jermar 214
 * Insert timeout handler f (with argument arg)
215
 * to timeout list and make it execute in
107 decky 216
 * time microseconds (or slightly more).
217
 *
411 jermar 218
 * @param t    Timeout structure.
404 jermar 219
 * @param time Number of usec in the future to execute
107 decky 220
 *             the handler.
221
 * @param f    Timeout handler function.
222
 * @param arg  Timeout handler argument.
223
 *
1 jermar 224
 */
1780 jermar 225
void timeout_register(timeout_t *t, uint64_t time, timeout_handler_t f, void *arg)
1 jermar 226
{
659 jermar 227
    timeout_t *hlp = NULL;
1 jermar 228
    link_t *l, *m;
413 jermar 229
    ipl_t ipl;
1780 jermar 230
    uint64_t sum;
1 jermar 231
 
413 jermar 232
    ipl = interrupts_disable();
15 jermar 233
    spinlock_lock(&CPU->timeoutlock);
1 jermar 234
    spinlock_lock(&t->lock);
125 jermar 235
 
1 jermar 236
    if (t->cpu)
103 jermar 237
        panic("t->cpu != 0");
1 jermar 238
 
15 jermar 239
    t->cpu = CPU;
1 jermar 240
    t->ticks = us2ticks(time);
241
 
242
    t->handler = f;
243
    t->arg = arg;
125 jermar 244
 
1 jermar 245
    /*
246
     * Insert t into the active timeouts list according to t->ticks.
247
     */
248
    sum = 0;
15 jermar 249
    l = CPU->timeout_active_head.next;
250
    while (l != &CPU->timeout_active_head) {
1 jermar 251
        hlp = list_get_instance(l, timeout_t, link);
252
        spinlock_lock(&hlp->lock);
253
        if (t->ticks < sum + hlp->ticks) {
254
            spinlock_unlock(&hlp->lock);
255
            break;
256
        }
257
        sum += hlp->ticks;
258
        spinlock_unlock(&hlp->lock);
259
        l = l->next;
260
    }
239 vana 261
 
1 jermar 262
    m = l->prev;
263
    list_prepend(&t->link, m); /* avoid using l->prev */
264
 
265
    /*
266
     * Adjust t->ticks according to ticks accumulated in h's predecessors.
267
     */
268
    t->ticks -= sum;
269
 
270
    /*
271
     * Decrease ticks of t's immediate succesor by t->ticks.
272
     */
15 jermar 273
    if (l != &CPU->timeout_active_head) {
1 jermar 274
        spinlock_lock(&hlp->lock);
275
        hlp->ticks -= t->ticks;
276
        spinlock_unlock(&hlp->lock);
277
    }
278
 
279
    spinlock_unlock(&t->lock);
15 jermar 280
    spinlock_unlock(&CPU->timeoutlock);
413 jermar 281
    interrupts_restore(ipl);
1 jermar 282
}
283
 
107 decky 284
 
411 jermar 285
/** Unregister timeout
107 decky 286
 *
287
 * Remove timeout from timeout list.
288
 *
289
 * @param t Timeout to unregister.
290
 *
411 jermar 291
 * @return true on success, false on failure.
107 decky 292
 */
411 jermar 293
bool timeout_unregister(timeout_t *t)
1 jermar 294
{
295
    timeout_t *hlp;
296
    link_t *l;
413 jermar 297
    ipl_t ipl;
1 jermar 298
 
299
grab_locks:
413 jermar 300
    ipl = interrupts_disable();
1 jermar 301
    spinlock_lock(&t->lock);
302
    if (!t->cpu) {
303
        spinlock_unlock(&t->lock);
413 jermar 304
        interrupts_restore(ipl);
411 jermar 305
        return false;
1 jermar 306
    }
307
    if (!spinlock_trylock(&t->cpu->timeoutlock)) {
308
        spinlock_unlock(&t->lock);
2336 mencl 309
        interrupts_restore(ipl);       
1 jermar 310
        goto grab_locks;
311
    }
312
 
313
    /*
314
     * Now we know for sure that t hasn't been activated yet
315
     * and is lurking in t->cpu->timeout_active_head queue.
316
     */
317
 
318
    l = t->link.next;
319
    if (l != &t->cpu->timeout_active_head) {
320
        hlp = list_get_instance(l, timeout_t, link);
321
        spinlock_lock(&hlp->lock);
322
        hlp->ticks += t->ticks;
323
        spinlock_unlock(&hlp->lock);
324
    }
325
 
326
    list_remove(&t->link);
327
    spinlock_unlock(&t->cpu->timeoutlock);
328
 
329
    timeout_reinitialize(t);
330
    spinlock_unlock(&t->lock);
331
 
413 jermar 332
    interrupts_restore(ipl);
411 jermar 333
    return true;
1 jermar 334
}
1702 cejka 335
 
2336 mencl 336
#endif
1731 jermar 337
/** @}
1702 cejka 338
 */