Subversion Repositories HelenOS

Rev

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

  1. /*
  2.  * Copyright (C) 2001-2004 Jakub Jermar
  3.  * Copyright (C) 2007 Vojtech Mencl
  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.  
  30. /** @addtogroup time
  31.  * @{
  32.  */
  33.  
  34. /**
  35.  * @file
  36.  * @brief   Timeout management functions.
  37.  */
  38.  
  39. #include <time/timeout.h>
  40. #include <arch/types.h>
  41. #include <config.h>
  42. #include <panic.h>
  43. #include <synch/spinlock.h>
  44. #include <func.h>
  45. #include <cpu.h>
  46. #include <arch/asm.h>
  47. #include <arch.h>
  48.  
  49.  
  50. /** Initialize timeouts
  51.  *
  52.  * Initialize kernel timeouts.
  53.  *
  54.  */
  55. void timeout_init(void)
  56. {
  57.     spinlock_initialize(&CPU->timeoutlock, "timeout_lock");
  58.  
  59. #if defined CONFIG_TIMEOUT_AVL_TREE
  60.     avltree_create(&CPU->timeout_active_tree);
  61. #elif defined CONFIG_TIMEOUT_FAVL_TREE
  62.     favltree_create(&CPU->timeout_active_tree);
  63. #elif defined CONFIG_TIMEOUT_EXTAVL_TREE
  64.     extavltree_create(&CPU->timeout_active_tree);
  65. #elif defined CONFIG_TIMEOUT_EXTAVLREL_TREE
  66.     extavlreltree_create(&CPU->timeout_active_tree);
  67. #else
  68.     list_initialize(&CPU->timeout_active_head);
  69. #endif
  70. }
  71.  
  72.  
  73. /** Reinitialize timeout
  74.  *
  75.  * Initialize all members except the lock.
  76.  *
  77.  * @param t Timeout to be initialized.
  78.  *
  79.  */
  80. void timeout_reinitialize(timeout_t *t)
  81. {
  82.     t->cpu = NULL;
  83.     t->handler = NULL;
  84.     t->arg = NULL;
  85.  
  86. #if defined CONFIG_TIMEOUT_AVL_TREE
  87.     avltree_node_initialize(&t->node);
  88. #elif defined CONFIG_TIMEOUT_FAVL_TREE
  89.     favltree_node_initialize(&t->node);
  90. #elif defined CONFIG_TIMEOUT_EXTAVL_TREE
  91.     extavltree_node_initialize(&t->node);
  92. #elif defined CONFIG_TIMEOUT_EXTAVLREL_TREE
  93.     extavlreltree_node_initialize(&t->node);
  94. #else
  95.     t->ticks = 0;
  96.     link_initialize(&t->link);
  97. #endif
  98. }
  99.  
  100.  
  101. /** Initialize timeout
  102.  *
  103.  * Initialize all members including the lock.
  104.  *
  105.  * @param t Timeout to be initialized.
  106.  *
  107.  */
  108. void timeout_initialize(timeout_t *t)
  109. {
  110.     spinlock_initialize(&t->lock, "timeout_t_lock");
  111.     timeout_reinitialize(t);
  112. }
  113.  
  114. #if defined CONFIG_TIMEOUT_AVL_TREE || \
  115.     defined CONFIG_TIMEOUT_FAVL_TREE || \
  116.     defined CONFIG_TIMEOUT_EXTAVL_TREE || \
  117.     defined CONFIG_TIMEOUT_EXTAVLREL_TREE
  118.  
  119. /** Register timeout
  120.  *
  121.  * Insert timeout handler f (with argument arg)
  122.  * to timeout tree and make it execute in
  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;
  135.  
  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;
  146.     t->node.key = us2ticks(time);
  147.  
  148.     /*
  149.      * Insert timeout into tree structure.
  150.      */
  151. #if defined CONFIG_TIMEOUT_AVL_TREE
  152.     avltree_insert(&CPU->timeout_active_tree,&t->node);
  153. #elif defined CONFIG_TIMEOUT_FAVL_TREE
  154.     favltree_insert(&CPU->timeout_active_tree,&t->node);
  155. #elif defined CONFIG_TIMEOUT_EXTAVL_TREE
  156.     extavltree_insert(&CPU->timeout_active_tree,&t->node);
  157. #elif defined CONFIG_TIMEOUT_EXTAVLREL_TREE
  158.     extavlreltree_insert(&CPU->timeout_active_tree,&t->node);
  159. #endif
  160.  
  161.     spinlock_unlock(&t->lock);
  162.     spinlock_unlock(&CPU->timeoutlock);
  163.     interrupts_restore(ipl);
  164. }
  165.  
  166.  
  167. /** Unregister timeout
  168.  *
  169.  * Remove timeout from timeout tree structure.
  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.  
  197.     /*
  198.      * Delete timeout from tree structure.
  199.      */
  200. #if defined CONFIG_TIMEOUT_AVL_TREE
  201.     avltree_delete(&t->cpu->timeout_active_tree,&t->node);
  202. #elif defined CONFIG_TIMEOUT_FAVL_TREE
  203.     favltree_delete(&t->cpu->timeout_active_tree,&t->node);
  204. #elif defined CONFIG_TIMEOUT_EXTAVL_TREE
  205.     extavltree_delete(&t->cpu->timeout_active_tree,&t->node);
  206. #elif defined CONFIG_TIMEOUT_EXTAVLREL_TREE
  207.     extavlreltree_delete(&t->cpu->timeout_active_tree,&t->node);
  208. #endif
  209.  
  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.  
  221. /** Register timeout
  222.  *
  223.  * Insert timeout handler f (with argument arg)
  224.  * to timeout list and make it execute in
  225.  * time microseconds (or slightly more).
  226.  *
  227.  * @param t    Timeout structure.
  228.  * @param time Number of usec in the future to execute
  229.  *             the handler.
  230.  * @param f    Timeout handler function.
  231.  * @param arg  Timeout handler argument.
  232.  *
  233.  */
  234. void timeout_register(timeout_t *t, uint64_t time, timeout_handler_t f, void *arg)
  235. {
  236.     timeout_t *hlp = NULL;
  237.     link_t *l, *m;
  238.     ipl_t ipl;
  239.     uint64_t sum;
  240.  
  241.     ipl = interrupts_disable();
  242.     spinlock_lock(&CPU->timeoutlock);
  243.     spinlock_lock(&t->lock);
  244.  
  245.     if (t->cpu)
  246.         panic("t->cpu != 0");
  247.  
  248.     t->cpu = CPU;
  249.     t->ticks = us2ticks(time);
  250.    
  251.     t->handler = f;
  252.     t->arg = arg;
  253.  
  254.     /*
  255.      * Insert t into the active timeouts list according to t->ticks.
  256.      */
  257.     sum = 0;
  258.     l = CPU->timeout_active_head.next;
  259.     while (l != &CPU->timeout_active_head) {
  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.     }
  270.  
  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.      */
  282.     if (l != &CPU->timeout_active_head) {
  283.         spinlock_lock(&hlp->lock);
  284.         hlp->ticks -= t->ticks;
  285.         spinlock_unlock(&hlp->lock);
  286.     }
  287.  
  288.     spinlock_unlock(&t->lock);
  289.     spinlock_unlock(&CPU->timeoutlock);
  290.     interrupts_restore(ipl);
  291. }
  292.  
  293.  
  294. /** Unregister timeout
  295.  *
  296.  * Remove timeout from timeout list.
  297.  *
  298.  * @param t Timeout to unregister.
  299.  *
  300.  * @return true on success, false on failure.
  301.  */
  302. bool timeout_unregister(timeout_t *t)
  303. {
  304.     timeout_t *hlp;
  305.     link_t *l;
  306.     ipl_t ipl;
  307.  
  308. grab_locks:
  309.     ipl = interrupts_disable();
  310.     spinlock_lock(&t->lock);
  311.     if (!t->cpu) {
  312.         spinlock_unlock(&t->lock);
  313.         interrupts_restore(ipl);
  314.         return false;
  315.     }
  316.     if (!spinlock_trylock(&t->cpu->timeoutlock)) {
  317.         spinlock_unlock(&t->lock);
  318.         interrupts_restore(ipl);       
  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.  
  341.     interrupts_restore(ipl);
  342.     return true;
  343. }
  344.  
  345. #endif
  346. /** @}
  347.  */
  348.