Subversion Repositories HelenOS

Rev

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.  
  30. /** @addtogroup genericddi
  31.  * @{
  32.  */
  33. /** @file
  34.  */
  35.  
  36. #include <arch.h>
  37. #include <config.h>
  38. #include <arch/types.h>
  39. #include <arch/asm.h>
  40. #include <proc/tasklet.h>
  41. #include <synch/spinlock.h>
  42. #include <time/delay.h>
  43. #include <proc/thread.h>
  44. #include <panic.h>
  45. #include <print.h>
  46. #include <synch/waitq.h>
  47. #include <cpu.h>
  48. #include <proc/scheduler.h>
  49.  
  50. /** Timeout length in the tasklet thread */
  51. #define TASKLET_THREAD_SLEEPDELAY 10000
  52. ///** Priority of the tasklet thread */
  53. #define TASKLET_THREAD_PRIORITY 1
  54.  
  55.  
  56. /** Tasklet state enum */
  57. typedef enum  {
  58. TASKLET_STATE_NOTACTIVE = 0,
  59. TASKLET_STATE_SCHEDULED = 1,
  60. TASKLET_STATE_RUNNING = 2,
  61. TASKLET_STATE_DISABLED = 4
  62. } tasklet_state_enum;
  63.  
  64. /** Spinlock protecting list of tasklets */
  65. SPINLOCK_INITIALIZE(tasklet_lock);
  66.  
  67. /** array of tasklet lists for every CPU */
  68. tasklet_descriptor_t** tasklet_list;
  69.  
  70. /** Initializes tasklets - except for the tasklet thread */
  71. void tasklet_init(void)
  72. {
  73.     int i;
  74.     tasklet_list=malloc(sizeof(tasklet_descriptor_t*)*config.cpu_count,0);
  75.     if (tasklet_list==0)
  76.         panic_printf("tasklet list mem not allocated\n");
  77.     for(i=0;i<config.cpu_count;i++) {
  78.         tasklet_list[i]=0;
  79.     }
  80.     spinlock_initialize(&tasklet_lock, "tasklet_lock");
  81.  
  82. }
  83.  
  84. /**
  85. * Creates and runs the tasklet thread
  86. *
  87. *  @param kernel_task Pointer to the kernel task - for create_thread
  88. */
  89. void tasklet_run_tasklet_thread(task_t * kernel_task)
  90. {
  91.     //create the tasklet_thread, it's wired to the current cpu, we'll migrate it ourselves
  92.     thread_t* t= thread_create(&tasklet_thread, NULL, kernel_task, THREAD_FLAG_WIRED, "tasklet_thread", false);
  93.     if (t==NULL) {
  94.         //wtf?
  95.         panic_printf("tasklet thread not created\n");
  96.     } else {
  97.         spinlock_lock(&t->lock);           
  98.         t->cpu = &cpus[0];
  99.         t->priority = TASKLET_THREAD_PRIORITY;
  100.         spinlock_unlock(&t->lock);
  101.         thread_ready(t);
  102.     }
  103. }
  104.  
  105. /** Thread which keeps executing scheduled enabled tasklets
  106. * @param data not used
  107. */
  108. void tasklet_thread(void* data)
  109. {
  110. #ifdef CONFIG_SMP
  111.     int current_cpu, new_cpu ;
  112.     cpu_t *cpu;
  113. #endif
  114.     waitq_t  wq;
  115.     waitq_initialize(&wq);
  116.    
  117.     while (true) {
  118.         tasklet_do();
  119. #ifdef CONFIG_SMP
  120.         if (config.cpu_active>1) {
  121.             current_cpu = CPU->id;
  122.             //find the first cpu with nonempty tasklet_list
  123.             for (new_cpu = (current_cpu + 1) % config.cpu_active; new_cpu!=current_cpu && tasklet_list[new_cpu]==0;
  124.                     new_cpu=(new_cpu + 1)% config.cpu_active);
  125.  
  126.             if (new_cpu!=current_cpu) {
  127.                 //we need to migrate this thread to CPU with id new_cpu
  128.                 cpu = &cpus[new_cpu];
  129.  
  130.                 spinlock_lock(&THREAD->lock);
  131.                 //put tasklet_thread on the new_cpu
  132.                 THREAD->cpu = cpu;
  133.                 spinlock_unlock(&THREAD->lock);
  134.             }
  135.         }
  136. #endif
  137.         waitq_sleep_timeout(&wq, (uint32_t)TASKLET_THREAD_SLEEPDELAY, 0);
  138.  
  139.  
  140.     }
  141. }
  142.  
  143. /** Initializes tasklet structure
  144. * @param func tasklet callback function to be called
  145. * @param data pointer to be passed to the tasklet function
  146. */
  147. tasklet_descriptor_t* tasklet_register(void (*func)(void* data), void* data)
  148. {
  149.     tasklet_descriptor_t* tasklet=malloc(sizeof(tasklet_descriptor_t),0);
  150.     tasklet->data = data;
  151.     tasklet->func = func;
  152.     tasklet->state = TASKLET_STATE_NOTACTIVE;
  153.     tasklet->next = 0;
  154.     return tasklet;
  155. }
  156.  
  157. /** Schedules the tasklet for execution on current CPU
  158. * @param t tasklet to be scheduled
  159. */
  160. void tasklet_schedule(tasklet_descriptor_t* t)
  161. {
  162.     spinlock_lock(&tasklet_lock);
  163.     //clear notactive, running and scheduled flags
  164.     t->state &= TASKLET_STATE_DISABLED;
  165.     //set the scheduled flag
  166.     t->state |= TASKLET_STATE_SCHEDULED;
  167.     t->next=tasklet_list[CPU->id];
  168.     tasklet_list[CPU->id]=t;
  169.     spinlock_unlock(&tasklet_lock);
  170. }
  171.  
  172. /** Tasklet will not be run, even if scheduled
  173. * @param t tasklet to be disabled
  174. */
  175. void tasklet_disable(tasklet_descriptor_t* t)
  176. {
  177.     spinlock_lock(&tasklet_lock);
  178.     //set the disabled flag
  179.     t->state |= TASKLET_STATE_DISABLED;
  180.     spinlock_unlock(&tasklet_lock);
  181. }
  182.  
  183. /** Tasklet will be run if scheduled
  184. * @param t tasklet to be enabled
  185. */
  186. void tasklet_enable(tasklet_descriptor_t* t)
  187. {
  188.     spinlock_lock(&tasklet_lock);
  189.     //clear the disabled flag
  190.     t->state &= ~TASKLET_STATE_DISABLED;
  191.     spinlock_unlock(&tasklet_lock);
  192. }
  193.  
  194.  
  195.  
  196.  
  197. /** Executes scheduled enabled tasklets on current CPU */
  198. void tasklet_do(void)
  199. {
  200.     spinlock_lock(&tasklet_lock);
  201.     tasklet_descriptor_t* t = tasklet_list[CPU->id];
  202.     //printf(".");
  203.     if (t) {
  204.         //empty the tasklet_list
  205.         tasklet_list[CPU->id]=0;
  206.         do {
  207.             if (!(t->state & TASKLET_STATE_DISABLED)) {
  208.                 if (t->func) {
  209.                     t->state = TASKLET_STATE_RUNNING;
  210.                     t->func(t->data);
  211.                     t->state = TASKLET_STATE_NOTACTIVE;
  212.                 } else
  213.                     panic_printf("tasklet func NULL\n");
  214.             } else {  
  215.                 //return it back to the queue of scheduled tasklets
  216.                 t->next = tasklet_list[CPU->id];
  217.                 tasklet_list[CPU->id] = t;
  218.             }
  219.             t=t->next;
  220.         }
  221.         while (t);
  222.     }
  223.     spinlock_unlock(&tasklet_lock);
  224. }
  225.  
  226. /** Frees the tasklet structure when no longer needed. The function doesn't provide
  227. *   any synchronization, the caller must be sure, the tasklet is not scheduled.
  228. *
  229. * @param tasklet to be freed
  230. */
  231. void tasklet_free(tasklet_descriptor_t* t)
  232. {
  233.     spinlock_lock(&tasklet_lock);
  234.     if (t->state == TASKLET_STATE_NOTACTIVE)
  235.         free(t);
  236.     else
  237.         panic_printf("attempting to free an active tasklet");
  238.     spinlock_unlock(&tasklet_lock);
  239. }
  240.  
  241.  
  242.