Subversion Repositories HelenOS

Rev

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

  1. /*
  2.  * Copyright (c) 2007 Jan Hudecek
  3.  * Copyright (c) 2006 Jakub 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. /** @addtogroup sync
  30.  * @{
  31.  */
  32. /** @file
  33.  */
  34.  
  35. #include <synch/rcu.h>
  36. #include <synch/waitq.h>
  37. #include <arch.h>
  38. #include <config.h>
  39. #include <arch/types.h>
  40. #include <proc/tasklet.h>
  41. #include <synch/spinlock.h>
  42. #include <time/delay.h>
  43. #include <panic.h>
  44. #include <print.h>
  45.  
  46. SPINLOCK_INITIALIZE(rcu_global_lock);
  47.  
  48. typedef struct rcu_callback_list {
  49.     struct rcu_callback_list* next;
  50.     void (*func)(void*);
  51.     void* data;
  52. } rcu_callback_list_t;
  53.  
  54. typedef struct  {
  55. #ifdef CONFIG_SMP
  56.     bool* cpu_mask;
  57. #endif
  58.     rcu_callback_list_t* next_batch, *current_batch, *done_batch;
  59. } rcu_global_t;
  60.  
  61.  
  62. rcu_global_t* _rcu_global;
  63. tasklet_descriptor_t* rcu_tasklet_desc;
  64.  
  65. void rcu_init(void)
  66. {
  67. #ifdef CONFIG_SMP
  68.     int i;
  69. #endif
  70.  
  71.     _rcu_global = malloc(sizeof(rcu_global_t),0);
  72.     _rcu_global->done_batch = NULL;
  73.     _rcu_global->current_batch = NULL;
  74.     _rcu_global->next_batch = NULL;
  75.     spinlock_initialize(&rcu_global_lock, "rcu_global_lock");
  76.  
  77.     rcu_tasklet_desc = tasklet_register(&rcu_tasklet, NULL);
  78.     tasklet_disable(rcu_tasklet_desc);
  79.  
  80. #ifdef CONFIG_SMP
  81.     _rcu_global->cpu_mask = malloc (sizeof(bool)*config.cpu_count,0);
  82.     for (i=0;i<config.cpu_count;i++) {
  83.         _rcu_global->cpu_mask[i]=false;
  84.     }
  85. #else
  86.     tasklet_schedule(rcu_tasklet_desc);
  87.  
  88. #endif
  89.     tasklet_enable(rcu_tasklet_desc);
  90. }
  91.  
  92. void rcu_synchronize(void)
  93. {
  94. #ifdef CONFIG_SMP
  95.     waitq_t *wq = malloc(sizeof(waitq_t),0);
  96.     waitq_initialize(wq);
  97.     rcu_sync_callback(&rcu_synchronize_callback_function, wq);
  98.     printf("going to sleep, tlock:%x, wqlock:%x\n", THREAD->lock.val, wq->lock.val);
  99.     waitq_sleep(wq);
  100.     printf("woken up\n");
  101.     free(wq);
  102. #endif
  103. }
  104.  
  105. #ifdef CONFIG_SMP
  106. void rcu_synchronize_callback_function(void* waitq)
  107. {
  108.     printf("waking up, wq:%x, wq->head:%x, next:%x, tlock:%x, wqlock:%x\n",
  109.         waitq,
  110.         ((waitq_t*)waitq)->head,
  111.         ((link_t)((waitq_t*)waitq)->head).next,
  112.         THREAD->lock.val,
  113.         ((waitq_t*)waitq)->lock.val );
  114.     waitq_wakeup(((waitq_t*)waitq), WAKEUP_ALL);
  115. }
  116. #endif
  117.  
  118. void rcu_sync_callback(void (*func)(void* data), void* data)
  119. {
  120. #ifndef CONFIG_SMP
  121.     func(data);
  122. #else
  123.     int i;
  124.     rcu_callback_list_t *rd;
  125.     rd = malloc(sizeof(rcu_callback_list_t), 0);
  126.     rd->func = func;
  127.     rd->data = data;
  128.     rd->next = NULL;
  129.  
  130.     printf("synccallback locking \n");
  131.     spinlock_lock(&rcu_global_lock);
  132.  
  133.     rd->next = _rcu_global->next_batch;
  134.     _rcu_global->next_batch = rd;
  135.  
  136.     if (_rcu_global->current_batch == NULL) {
  137.         _rcu_global->current_batch = _rcu_global->next_batch;
  138.         _rcu_global->next_batch = NULL;
  139.         printf("setting callback %x as current\n",&rd->func);
  140.         for (i=0;i<config.cpu_count;i++)
  141.             _rcu_global->cpu_mask[i]=false;
  142.  
  143.         //we've surely passed the quiescent point just by running this method
  144.         rcu_passQS();
  145.     }
  146.     for (i=0;i<config.cpu_count;i++) {
  147.         tasklet_schedule_SMP(rcu_tasklet_desc, i);
  148.     }
  149.     spinlock_unlock(&rcu_global_lock);
  150.     printf ("sync callback called,unlocking, state:%x \n",rcu_tasklet_desc->state);
  151. #endif
  152. }
  153.  
  154.     //TODO: polishing, comments
  155.  
  156. void rcu_tasklet(void* data)
  157. {
  158.     rcu_callback_list_t* rd;
  159.     bool passed_all_QS;
  160. #ifdef CONFIG_SMP
  161.     int i;
  162. #endif
  163.     rcu_passQS();
  164.     passed_all_QS = true;
  165.     printf("tasklet locking \n");
  166.     spinlock_lock(&rcu_global_lock);
  167. #ifdef CONFIG_SMP
  168.  
  169.     for (i = 0; i < config.cpu_active; i++)
  170.         passed_all_QS &= _rcu_global->cpu_mask[i];
  171. #endif
  172.     if (passed_all_QS) {
  173.         if (_rcu_global->done_batch) {
  174.             rd = _rcu_global->done_batch;
  175.             while (rd->next) rd = rd->next;
  176.  
  177.             //append the current list to done list
  178.             rd->next = _rcu_global->current_batch;
  179.         } else
  180.             _rcu_global->done_batch = _rcu_global->current_batch;
  181.         printf("setting callback %x as done\n",&_rcu_global->current_batch->func);
  182.         _rcu_global->current_batch = _rcu_global->next_batch;
  183.         _rcu_global->next_batch = NULL;
  184. #ifdef CONFIG_SMP
  185.  
  186.         for (i=0;i<config.cpu_count;i++)
  187.             _rcu_global->cpu_mask[i]=false;
  188. #endif
  189.         //we've surely passed the quiescent point just by running this method
  190.         rcu_passQS();
  191.     }
  192.  
  193.     spinlock_unlock(&rcu_global_lock);
  194.     printf("tasklet unlocking \n");
  195. }
  196.  
  197. inline void rcu_passQS(void)
  198. {
  199. #ifdef CONFIG_SMP
  200.     _rcu_global->cpu_mask[CPU->id] = true;
  201. #endif
  202. }
  203.  
  204. void rcu_run_callbacks(void)
  205. {
  206.     rcu_callback_list_t* rd;
  207.     rcu_passQS();
  208.     if (_rcu_global->done_batch) {
  209.         printf("run callbacks locking\n");
  210.         spinlock_lock(&rcu_global_lock);
  211.         rd = _rcu_global->done_batch;
  212.         _rcu_global->done_batch = NULL;
  213.         spinlock_unlock(&rcu_global_lock);
  214.         printf("run callbacks unlocking\n");
  215.         for (; rd; rd=rd->next) {
  216.             printf("calling %x \n",&rd->func);
  217.             rd->func(&rd->data);
  218.         }
  219.     }
  220. }
  221.  
  222.  
  223.