Subversion Repositories HelenOS

Rev

Rev 2265 | Rev 2315 | 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\n");
  99.     waitq_sleep(wq);
  100.     printf("woken up\n");
  101. #endif
  102. }
  103.  
  104. #ifdef CONFIG_SMP
  105. void rcu_synchronize_callback_function(void* waitq)
  106. {
  107.     printf("waking up\n");
  108.     waitq_wakeup(((waitq_t*)waitq), WAKEUP_ALL_INC_MISSED);
  109. }
  110. #endif
  111.  
  112. void rcu_sync_callback(void (*func)(void* data), void* data)
  113. {
  114. #ifndef CONFIG_SMP
  115.     func(data);
  116. #else
  117.     int i;
  118.     rcu_callback_list_t *rd;
  119.     rd = malloc(sizeof(rcu_callback_list_t), 0);
  120.     rd->func = func;
  121.     rd->data = data;
  122.     rd->next = NULL;
  123.     printf("synccallback locking \n");
  124.     spinlock_lock(&rcu_global_lock);
  125.     rd->next = _rcu_global->next_batch;
  126.     _rcu_global->next_batch = rd;
  127.  
  128.     if (_rcu_global->current_batch == NULL) {
  129.         _rcu_global->current_batch = _rcu_global->next_batch;
  130.         _rcu_global->next_batch = NULL;
  131.         printf("setting callback %x as current\n",&rd->func);
  132.         for (i=0;i<config.cpu_count;i++)
  133.             _rcu_global->cpu_mask[i]=false;
  134.  
  135.         //we've surely passed the quiescent point just by running this method
  136.         rcu_passQS();
  137.     }
  138.     for (i=0;i<config.cpu_count;i++) {
  139.         tasklet_schedule_SMP(rcu_tasklet_desc, i);
  140.     }
  141.     spinlock_unlock(&rcu_global_lock);
  142.     printf ("sync callback called,unlocking, state:%x \n",rcu_tasklet_desc->state);
  143. #endif
  144. }
  145.  
  146.     //TODO: polishing, comments
  147.  
  148. void rcu_tasklet(void* data)
  149. {
  150.     rcu_callback_list_t* rd;
  151.     bool passed_all_QS;
  152. #ifdef CONFIG_SMP
  153.     int i;
  154. #endif
  155.     rcu_passQS();
  156.     passed_all_QS = true;
  157.     printf("tasklet locking \n");
  158.     spinlock_lock(&rcu_global_lock);
  159. #ifdef CONFIG_SMP
  160.  
  161.     for (i = 0; i < config.cpu_active; i++)
  162.         passed_all_QS &= _rcu_global->cpu_mask[i];
  163. #endif
  164.     if (passed_all_QS) {
  165.         if (_rcu_global->done_batch) {
  166.             rd = _rcu_global->done_batch;
  167.             while (rd->next) rd = rd->next;
  168.  
  169.             //append the current list to done list
  170.             rd->next = _rcu_global->current_batch;
  171.         } else
  172.             _rcu_global->done_batch = _rcu_global->current_batch;
  173.         printf("setting callback %x as done\n",&_rcu_global->current_batch->func);
  174.         _rcu_global->current_batch = NULL;
  175.     }
  176.  
  177.     _rcu_global->current_batch = _rcu_global->next_batch;
  178.     _rcu_global->next_batch = NULL;
  179.  
  180.     if (_rcu_global->current_batch == NULL) {
  181.         //there are no rcu callbacks registered, there is no need to monitor QS
  182.         printf("tasklet idle disabling \n");
  183. //      tasklet_disable(rcu_tasklet_desc);
  184.         spinlock_unlock(&rcu_global_lock);
  185.     } else
  186.         spinlock_unlock(&rcu_global_lock);
  187.     printf("tasklet unlocking \n");
  188. }
  189.  
  190. inline void rcu_passQS(void)
  191. {
  192. #ifdef CONFIG_SMP
  193.     _rcu_global->cpu_mask[CPU->id] = true;
  194. #endif
  195. }
  196.  
  197. void rcu_run_callbacks(void)
  198. {
  199.     rcu_callback_list_t* rd;
  200.     rcu_passQS();
  201.     if (_rcu_global->done_batch) {
  202.         printf(".");
  203.         spinlock_lock(&rcu_global_lock);
  204.         for (rd = _rcu_global->done_batch; rd; rd=rd->next) {
  205.             printf("calling %x \n",&rd->func);
  206.             rd->func(&rd->data);
  207.         }
  208.         _rcu_global->done_batch = NULL;
  209.         spinlock_unlock(&rcu_global_lock);
  210.         printf(":");
  211.     }
  212. }
  213.  
  214.  
  215.