Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/time/timeout.c

    rda1bafb rd99c1d2  
    3333/**
    3434 * @file
    35  * @brief Timeout management functions.
     35 * @brief               Timeout management functions.
    3636 */
    3737
     
    5353void timeout_init(void)
    5454{
    55         irq_spinlock_initialize(&CPU->timeoutlock, "cpu.timeoutlock");
     55        spinlock_initialize(&CPU->timeoutlock, "timeout_lock");
    5656        list_initialize(&CPU->timeout_active_head);
    5757}
    5858
    59 /** Reinitialize timeout
     59
     60/** Reinitialize timeout
    6061 *
    6162 * Initialize all members except the lock.
    6263 *
    63  * @param timeout Timeout to be initialized.
    64  *
    65  */
    66 void timeout_reinitialize(timeout_t *timeout)
    67 {
    68         timeout->cpu = NULL;
    69         timeout->ticks = 0;
    70         timeout->handler = NULL;
    71         timeout->arg = NULL;
    72         link_initialize(&timeout->link);
    73 }
     64 * @param t             Timeout to be initialized.
     65 *
     66 */
     67void timeout_reinitialize(timeout_t *t)
     68{
     69        t->cpu = NULL;
     70        t->ticks = 0;
     71        t->handler = NULL;
     72        t->arg = NULL;
     73        link_initialize(&t->link);
     74}
     75
    7476
    7577/** Initialize timeout
     
    7779 * Initialize all members including the lock.
    7880 *
    79  * @param timeout Timeout to be initialized.
    80  *
    81  */
    82 void timeout_initialize(timeout_t *timeout)
    83 {
    84         irq_spinlock_initialize(&timeout->lock, "timeout_t_lock");
    85         timeout_reinitialize(timeout);
    86 }
     81 * @param t             Timeout to be initialized.
     82 *
     83 */
     84void timeout_initialize(timeout_t *t)
     85{
     86        spinlock_initialize(&t->lock, "timeout_t_lock");
     87        timeout_reinitialize(t);
     88}
     89
    8790
    8891/** Register timeout
     
    9295 * time microseconds (or slightly more).
    9396 *
    94  * @param timeout Timeout structure.
    95  * @param time    Number of usec in the future to execute the handler.
    96  * @param handler Timeout handler function.
    97  * @param arg     Timeout handler argument.
    98  *
    99  */
    100 void timeout_register(timeout_t *timeout, uint64_t time,
    101     timeout_handler_t handler, void *arg)
    102 {
    103         irq_spinlock_lock(&CPU->timeoutlock, true);
    104         irq_spinlock_lock(&timeout->lock, false);
     97 * @param t             Timeout structure.
     98 * @param time          Number of usec in the future to execute the handler.
     99 * @param f             Timeout handler function.
     100 * @param arg           Timeout handler argument.
     101 *
     102 */
     103void
     104timeout_register(timeout_t *t, uint64_t time, timeout_handler_t f, void *arg)
     105{
     106        timeout_t *hlp = NULL;
     107        link_t *l, *m;
     108        ipl_t ipl;
     109        uint64_t sum;
     110
     111        ipl = interrupts_disable();
     112        spinlock_lock(&CPU->timeoutlock);
     113        spinlock_lock(&t->lock);
     114
     115        if (t->cpu)
     116                panic("Unexpected: t->cpu != 0.");
     117
     118        t->cpu = CPU;
     119        t->ticks = us2ticks(time);
    105120       
    106         if (timeout->cpu)
    107                 panic("Unexpected: timeout->cpu != 0.");
    108        
    109         timeout->cpu = CPU;
    110         timeout->ticks = us2ticks(time);
    111        
    112         timeout->handler = handler;
    113         timeout->arg = arg;
    114        
    115         /*
    116          * Insert timeout into the active timeouts list according to timeout->ticks.
    117          */
    118         uint64_t sum = 0;
    119         timeout_t *target = NULL;
    120         link_t *cur;
    121         for (cur = CPU->timeout_active_head.next;
    122             cur != &CPU->timeout_active_head; cur = cur->next) {
    123                 target = list_get_instance(cur, timeout_t, link);
    124                 irq_spinlock_lock(&target->lock, false);
    125                
    126                 if (timeout->ticks < sum + target->ticks) {
    127                         irq_spinlock_unlock(&target->lock, false);
     121        t->handler = f;
     122        t->arg = arg;
     123
     124        /*
     125         * Insert t into the active timeouts list according to t->ticks.
     126         */
     127        sum = 0;
     128        l = CPU->timeout_active_head.next;
     129        while (l != &CPU->timeout_active_head) {
     130                hlp = list_get_instance(l, timeout_t, link);
     131                spinlock_lock(&hlp->lock);
     132                if (t->ticks < sum + hlp->ticks) {
     133                        spinlock_unlock(&hlp->lock);
    128134                        break;
    129135                }
    130                
    131                 sum += target->ticks;
    132                 irq_spinlock_unlock(&target->lock, false);
    133         }
    134        
    135         /* Avoid using cur->prev directly */
    136         link_t *prev = cur->prev;
    137         list_prepend(&timeout->link, prev);
    138        
    139         /*
    140          * Adjust timeout->ticks according to ticks
    141          * accumulated in target's predecessors.
    142          */
    143         timeout->ticks -= sum;
    144        
    145         /*
    146          * Decrease ticks of timeout's immediate succesor by timeout->ticks.
    147          */
    148         if (cur != &CPU->timeout_active_head) {
    149                 irq_spinlock_lock(&target->lock, false);
    150                 target->ticks -= timeout->ticks;
    151                 irq_spinlock_unlock(&target->lock, false);
    152         }
    153        
    154         irq_spinlock_unlock(&timeout->lock, false);
    155         irq_spinlock_unlock(&CPU->timeoutlock, true);
    156 }
     136                sum += hlp->ticks;
     137                spinlock_unlock(&hlp->lock);
     138                l = l->next;
     139        }
     140
     141        m = l->prev;
     142        list_prepend(&t->link, m); /* avoid using l->prev */
     143
     144        /*
     145         * Adjust t->ticks according to ticks accumulated in h's predecessors.
     146         */
     147        t->ticks -= sum;
     148
     149        /*
     150         * Decrease ticks of t's immediate succesor by t->ticks.
     151         */
     152        if (l != &CPU->timeout_active_head) {
     153                spinlock_lock(&hlp->lock);
     154                hlp->ticks -= t->ticks;
     155                spinlock_unlock(&hlp->lock);
     156        }
     157
     158        spinlock_unlock(&t->lock);
     159        spinlock_unlock(&CPU->timeoutlock);
     160        interrupts_restore(ipl);
     161}
     162
    157163
    158164/** Unregister timeout
     
    160166 * Remove timeout from timeout list.
    161167 *
    162  * @param timeout Timeout to unregister.
    163  *
    164  * @return True on success, false on failure.
    165  *
    166  */
    167 bool timeout_unregister(timeout_t *timeout)
    168 {
     168 * @param t             Timeout to unregister.
     169 *
     170 * @return              True on success, false on failure.
     171 */
     172bool timeout_unregister(timeout_t *t)
     173{
     174        timeout_t *hlp;
     175        link_t *l;
     176        ipl_t ipl;
    169177        DEADLOCK_PROBE_INIT(p_tolock);
    170        
     178
    171179grab_locks:
    172         irq_spinlock_lock(&timeout->lock, true);
    173         if (!timeout->cpu) {
    174                 irq_spinlock_unlock(&timeout->lock, true);
     180        ipl = interrupts_disable();
     181        spinlock_lock(&t->lock);
     182        if (!t->cpu) {
     183                spinlock_unlock(&t->lock);
     184                interrupts_restore(ipl);
    175185                return false;
    176186        }
    177        
    178         if (!irq_spinlock_trylock(&timeout->cpu->timeoutlock)) {
    179                 irq_spinlock_unlock(&timeout->lock, true);
     187        if (!spinlock_trylock(&t->cpu->timeoutlock)) {
     188                spinlock_unlock(&t->lock);
     189                interrupts_restore(ipl);
    180190                DEADLOCK_PROBE(p_tolock, DEADLOCK_THRESHOLD);
    181191                goto grab_locks;
     
    183193       
    184194        /*
    185          * Now we know for sure that timeout hasn't been activated yet
    186          * and is lurking in timeout->cpu->timeout_active_head queue.
    187          */
     195         * Now we know for sure that t hasn't been activated yet
     196         * and is lurking in t->cpu->timeout_active_head queue.
     197         */
     198
     199        l = t->link.next;
     200        if (l != &t->cpu->timeout_active_head) {
     201                hlp = list_get_instance(l, timeout_t, link);
     202                spinlock_lock(&hlp->lock);
     203                hlp->ticks += t->ticks;
     204                spinlock_unlock(&hlp->lock);
     205        }
    188206       
    189         link_t *cur = timeout->link.next;
    190         if (cur != &timeout->cpu->timeout_active_head) {
    191                 timeout_t *tmp = list_get_instance(cur, timeout_t, link);
    192                 irq_spinlock_lock(&tmp->lock, false);
    193                 tmp->ticks += timeout->ticks;
    194                 irq_spinlock_unlock(&tmp->lock, false);
    195         }
    196        
    197         list_remove(&timeout->link);
    198         irq_spinlock_unlock(&timeout->cpu->timeoutlock, false);
    199        
    200         timeout_reinitialize(timeout);
    201         irq_spinlock_unlock(&timeout->lock, true);
    202        
     207        list_remove(&t->link);
     208        spinlock_unlock(&t->cpu->timeoutlock);
     209
     210        timeout_reinitialize(t);
     211        spinlock_unlock(&t->lock);
     212
     213        interrupts_restore(ipl);
    203214        return true;
    204215}
Note: See TracChangeset for help on using the changeset viewer.