Subversion Repositories HelenOS

Rev

Rev 2416 | Rev 2431 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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