Main Page | Modules | Class List | File List | Class Members | File Members | Related Pages

softirq.c

Go to the documentation of this file.
00001 /* $Id: softirq.c,v 1.15 2004/05/05 13:50:24 ch12 Exp $ */
00002 /*****************************************************************************/
00011 /* (c) 2003 Technische Universitaet Dresden
00012  * This file is part of DROPS, which is distributed under the terms of the
00013  * GNU General Public License 2. Please see the COPYING file for details.
00014  */
00015 
00035 /* L4 */
00036 #include <l4/env/errno.h>
00037 #include <l4/sys/syscalls.h>
00038 #include <l4/thread/thread.h>
00039 #include <l4/semaphore/semaphore.h>
00040 #include <l4/lock/lock.h>
00041 
00042 #include <l4/dde_linux/dde.h>
00043 
00044 /* Linux */
00045 #include <linux/config.h>
00046 #include <linux/mm.h>
00047 #include <linux/kernel_stat.h>
00048 #include <linux/interrupt.h>
00049 #include <linux/smp_lock.h>
00050 #include <linux/init.h>
00051 #include <linux/tqueue.h>
00052 
00053 /* local */
00054 #include "internal.h"
00055 #include "__config.h"
00056 
00068 static l4thread_t softirq_tid[SOFTIRQ_THREADS];
00069 
00071 static l4semaphore_t softirq_sema = L4SEMAPHORE_LOCKED;
00072 
00074 static int _initialized = 0;
00075 
00112 void __cpu_raise_softirq(unsigned cpu, int nr)
00113 {
00114   l4semaphore_up(&softirq_sema);
00115 }
00116 
00125 void raise_softirq(int nr)
00126 {
00127   /* original comment: I do not want to use atomic variables now, so that
00128      cli/sti */
00129   cli();
00130   __cpu_raise_softirq(0, nr);
00131   sti();
00132 }
00133 
00175 static struct tasklet_head tasklet_vec[NR_CPUS];
00176 
00179 static struct tasklet_head tasklet_hi_vec[NR_CPUS];
00180 
00182 static void tasklet_action(void)
00183 {
00184   struct tasklet_struct *list;
00185 
00186   LOGd(DEBUG_SOFTIRQ, "low prio tasklet exec entrance");
00187 
00188   cli();
00189   list = tasklet_vec[0].list;
00190   tasklet_vec[0].list = NULL;
00191   sti();
00192 
00193   while (list != NULL)
00194     {
00195       struct tasklet_struct *t = list;
00196 
00197       list = list->next;
00198 
00199       if (tasklet_trylock(t))
00200         {
00201           if (atomic_read(&t->count) == 0)
00202             {
00203               clear_bit(TASKLET_STATE_SCHED, &t->state);
00204 
00205               t->func(t->data);
00206               tasklet_unlock(t);
00207               continue;
00208             }
00209           tasklet_unlock(t);
00210         }
00211       cli();
00212       t->next = tasklet_vec[0].list;
00213       tasklet_vec[0].list = t;
00214       __cpu_raise_softirq(0, TASKLET_SOFTIRQ);
00215       sti();
00216     }
00217 }
00218 
00223 static int tasklet_hi_action(void)
00224 {
00225   struct tasklet_struct *list;
00226 
00227   if (!tasklet_hi_vec[0].list)
00228     /* no tasks */
00229     return 0;
00230 
00231   LOGd(DEBUG_SOFTIRQ, "hi prio tasklet exec entrance");
00232 
00233   cli();
00234   list = tasklet_hi_vec[0].list;
00235   tasklet_hi_vec[0].list = NULL;
00236   sti();
00237 
00238   while (list != NULL)
00239     {
00240       struct tasklet_struct *t = list;
00241 
00242       list = list->next;
00243 
00244       if (tasklet_trylock(t))
00245         {
00246           if (atomic_read(&t->count) == 0)
00247             {
00248               clear_bit(TASKLET_STATE_SCHED, &t->state);
00249 
00250               t->func(t->data);
00251               tasklet_unlock(t);
00252               continue;
00253             }
00254           tasklet_unlock(t);
00255         }
00256       cli();
00257       t->next = tasklet_hi_vec[0].list;
00258       tasklet_hi_vec[0].list = t;
00259       __cpu_raise_softirq(0, HI_SOFTIRQ);
00260       sti();
00261     }
00262 
00263   return !0;
00264 }
00265 
00273 void tasklet_init(struct tasklet_struct *t,
00274                   void (*func) (unsigned long), unsigned long data)
00275 {
00276   t->func = func;
00277   t->data = data;
00278   t->state = 0;
00279   atomic_set(&t->count, 0);
00280 }
00281 
00287 void tasklet_kill(struct tasklet_struct *t)
00288 {
00289 //      if (in_interrupt())
00290 //              printf("Attempt to kill tasklet from interrupt\n");
00291 
00292   while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
00293     {
00294 #if 0   /* original implementation uses schedule() */
00295       current->state = TASK_RUNNING;
00296       do
00297         {
00298           current->policy |= SCHED_YIELD;
00299           schedule();
00300         }
00301       while (test_bit(TASKLET_STATE_SCHED, &t->state));
00302 #else /* spin for tasklet while it is scheduled */
00303       do
00304         {
00305           /* release CPU on any way (like schedule() does in DDE) */
00306 # if SCHED_YIELD_OPT
00307           l4thread_usleep(SCHED_YIELD_TO);
00308 # else
00309           l4_yield();
00310 # endif
00311         }
00312       while (test_bit(TASKLET_STATE_SCHED, &t->state));
00313 #endif /* 0 */
00314     }
00315   tasklet_unlock_wait(t);
00316   clear_bit(TASKLET_STATE_SCHED, &t->state);
00317 }
00318 
00327 void tasklet_schedule(struct tasklet_struct *t)
00328 {
00329   if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
00330     {
00331       cli();
00332       t->next = tasklet_vec[0].list;
00333       tasklet_vec[0].list = t;
00334 
00335       /* raise softirq only on new 1st element */
00336       if (!t->next)
00337         __cpu_raise_softirq(0, TASKLET_SOFTIRQ);
00338       sti();
00339     }
00340 }
00341 
00342 /*****************************************************************************/
00351 /*****************************************************************************/
00352 void tasklet_hi_schedule(struct tasklet_struct *t)
00353 {
00354   if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
00355     {
00356       cli();
00357       t->next = tasklet_hi_vec[0].list;
00358       tasklet_hi_vec[0].list = t;
00359 
00360       /* raise softirq only on new 1st element */
00361       if (!t->next)
00362         __cpu_raise_softirq(0, HI_SOFTIRQ);
00363       sti();
00364     }
00365 }
00366 
00383 spinlock_t tqueue_lock = SPIN_LOCK_UNLOCKED;
00384 
00390 void __run_task_queue(task_queue * list)
00391 {
00392   struct list_head head, *next;
00393   unsigned long flags;
00394 
00395   spin_lock_irqsave(&tqueue_lock, flags);
00396   list_add(&head, list);
00397   list_del_init(list);
00398   spin_unlock_irqrestore(&tqueue_lock, flags);
00399 
00400   next = head.next;
00401   while (next != &head)
00402     {
00403       void (*f) (void *);
00404       struct tq_struct *p;
00405       void *data;
00406 
00407       p = list_entry(next, struct tq_struct, list);
00408       next = next->next;
00409       f = p->routine;
00410       data = p->data;
00411       wmb();
00412       p->sync = 0;
00413       if (f)
00414         f(data);
00415     }
00416 }
00417 
00428 static void dde_softirq_thread(int num)
00429 {
00430   softirq_tid[num] = l4thread_myself();
00431 
00432   if (l4dde_process_add_worker())
00433       Panic("l4dde_process_add_worker() failed");
00434 
00435   ++local_bh_count(smp_processor_id());
00436 
00437   /* we are up */
00438   if (l4thread_started(NULL)<0)
00439     Panic("softirq thread startup failed!");
00440 
00441   LOGd(DEBUG_MSG, "dde_softirq_thread[%d] "l4util_idfmt" running.", num,
00442        l4util_idstr(l4thread_l4_id(l4thread_myself())));
00443 
00444   /* softirq loop */
00445   while (1)
00446     {
00447       /* softirq _consumer_ */
00448       l4semaphore_down(&softirq_sema);
00449 
00450       /* low-priority tasks only if no high-priority available */
00451       if (!tasklet_hi_action())
00452         tasklet_action();
00453     }
00454 }
00455 
00465 int l4dde_softirq_init()
00466 {
00467 #if !(SOFTIRQ_THREADS == 1)
00468 #error SOFTIRQ_THREADS has to be 1
00469 #else
00470   int err;
00471 
00472   if (_initialized)
00473     return 0;
00474 
00475   /* create softirq thread */
00476   err = l4thread_create_long(L4THREAD_INVALID_ID,
00477                              (l4thread_fn_t) dde_softirq_thread,
00478                              ".softirq",
00479                              L4THREAD_INVALID_SP,
00480                              L4THREAD_DEFAULT_SIZE,
00481                              L4THREAD_DEFAULT_PRIO,
00482                              (void *) 0,
00483                              L4THREAD_CREATE_SYNC);
00484 
00485   if (err < 0)
00486     return err;
00487 
00488   ++_initialized;
00489   return 0;
00490 #endif
00491 }

Linux DDE, written by Christian Helmuth  © 2003 Technische Universitaet Dresden