Ignore:
File:
1 edited

Legend:

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

    rd99c1d2 rda1bafb  
    3333/**
    3434 * @file
    35  * @brief               Timeout management functions.
     35 * @brief Timeout management functions.
    3636 */
    3737
     
    5353void timeout_init(void)
    5454{
    55         spinlock_initialize(&CPU->timeoutlock, "timeout_lock");
     55        irq_spinlock_initialize(&CPU->timeoutlock, "cpu.timeoutlock");
    5656        list_initialize(&CPU->timeout_active_head);
    5757}
    5858
    59 
    60 /** Reinitialize timeout
     59/** Reinitialize timeout
    6160 *
    6261 * Initialize all members except the lock.
    6362 *
    64  * @param t             Timeout to be initialized.
    65  *
    66  */
    67 void 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 
     63 * @param timeout Timeout to be initialized.
     64 *
     65 */
     66void 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}
    7674
    7775/** Initialize timeout
     
    7977 * Initialize all members including the lock.
    8078 *
    81  * @param t             Timeout to be initialized.
    82  *
    83  */
    84 void timeout_initialize(timeout_t *t)
    85 {
    86         spinlock_initialize(&t->lock, "timeout_t_lock");
    87         timeout_reinitialize(t);
    88 }
    89 
     79 * @param timeout Timeout to be initialized.
     80 *
     81 */
     82void timeout_initialize(timeout_t *timeout)
     83{
     84        irq_spinlock_initialize(&timeout->lock, "timeout_t_lock");
     85        timeout_reinitialize(timeout);
     86}
    9087
    9188/** Register timeout
     
    9592 * time microseconds (or slightly more).
    9693 *
    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  */
    103 void
    104 timeout_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);
    120        
    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);
     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 */
     100void 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);
     105       
     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);
    134128                        break;
    135129                }
    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 
     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}
    163157
    164158/** Unregister timeout
     
    166160 * Remove timeout from timeout list.
    167161 *
    168  * @param t             Timeout to unregister.
    169  *
    170  * @return              True on success, false on failure.
    171  */
    172 bool timeout_unregister(timeout_t *t)
    173 {
    174         timeout_t *hlp;
    175         link_t *l;
    176         ipl_t ipl;
     162 * @param timeout Timeout to unregister.
     163 *
     164 * @return True on success, false on failure.
     165 *
     166 */
     167bool timeout_unregister(timeout_t *timeout)
     168{
    177169        DEADLOCK_PROBE_INIT(p_tolock);
    178 
     170       
    179171grab_locks:
    180         ipl = interrupts_disable();
    181         spinlock_lock(&t->lock);
    182         if (!t->cpu) {
    183                 spinlock_unlock(&t->lock);
    184                 interrupts_restore(ipl);
     172        irq_spinlock_lock(&timeout->lock, true);
     173        if (!timeout->cpu) {
     174                irq_spinlock_unlock(&timeout->lock, true);
    185175                return false;
    186176        }
    187         if (!spinlock_trylock(&t->cpu->timeoutlock)) {
    188                 spinlock_unlock(&t->lock);
    189                 interrupts_restore(ipl);
     177       
     178        if (!irq_spinlock_trylock(&timeout->cpu->timeoutlock)) {
     179                irq_spinlock_unlock(&timeout->lock, true);
    190180                DEADLOCK_PROBE(p_tolock, DEADLOCK_THRESHOLD);
    191181                goto grab_locks;
     
    193183       
    194184        /*
    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         }
    206        
    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);
     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         */
     188       
     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       
    214203        return true;
    215204}
Note: See TracChangeset for help on using the changeset viewer.