Annotation of OSKit-Mach/oskit/osenv_softirq.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 University of Utah and the Flux Group.
                      3:  * All rights reserved.
                      4:  *
                      5:  * This file is part of the Flux OSKit.  The OSKit is free software, also known
                      6:  * as "open source;" you can redistribute it and/or modify it under the terms
                      7:  * of the GNU General Public License (GPL), version 2, as published by the Free
                      8:  * Software Foundation (FSF).  To explore alternate licensing terms, contact
                      9:  * the University of Utah at [email protected] or +1-801-585-3271.
                     10:  *
                     11:  * The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY
                     12:  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
                     13:  * FOR A PARTICULAR PURPOSE.  See the GPL for more details.  You should have
                     14:  * received a copy of the GPL along with the OSKit; see the file COPYING.  If
                     15:  * not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA.
                     16:  */
                     17: 
                     18: /*
                     19:  * oskit Software Interrupt management for Mach.
                     20:  */
                     21: 
                     22: #include <oskit/error.h>
                     23: #include <oskit/debug.h>
                     24: #include <oskit/dev/dev.h>
                     25: #include <oskit/dev/softirq.h>
                     26: #include <oskit/machine/base_irq.h>
                     27: #include <stdio.h>
                     28: #include <string.h> /* ffs */
                     29: 
                     30: #include <machine/spl.h>
                     31: #include "ds_oskit.h"
                     32: 
                     33: 
                     34: /* Linked list of functions for a software interrupt.  */
                     35: struct softint_handler {
                     36:   void   (*func)(void *);
                     37:   void   *data;
                     38:   struct softint_handler *next;
                     39:   int    flags;
                     40: };
                     41: 
                     42: /* Array of pointers to lists of interrupt handlers.  */
                     43: static struct softint_handler *softint_handlers[SOFT_IRQ_COUNT];
                     44: 
                     45: /* Mask of allocated vectors, for the benefit of osenv_softirq_request()  */
                     46: static unsigned int softint_allocated = ((1 << OSENV_SOFT_IRQ_SOFTWARE)
                     47:                                         | (1 << OSENV_SOFT_IRQ_PTHREAD));
                     48: 
                     49: /* Pending softirqs that have been software scheduled.  */
                     50: static volatile unsigned int softint_pending;
                     51: 
                     52: static spl_t osenv_softintr_spl;
                     53: extern spl_t curr_ipl;
                     54: 
                     55: /* This is called from softclock_oskit, at splsoftclock.
                     56:    It's the hook to run any pending oskit software interrupt handlers.
                     57: 
                     58:    A software interrupt handler should obviously not allocate or deallocate
                     59:    a software interrupt.  It may schedule one of course.  */
                     60: void
                     61: oskit_softint (void)
                     62: {
                     63:   unsigned int pending;
                     64: 
                     65:   /* This must be an atomic instruction because hardware interrupts (splio)
                     66:      are enabled, and one could come in and call osenv_softirq_schedule
                     67:      while this frame is suspended by the interrupt.  */
                     68: 
                     69:   asm ("xchgl %0,%1"
                     70:        : "=&r" (pending), "=m" (softint_pending)
                     71:        : "0" (0), "1" (softint_pending));
                     72: 
                     73:   while (pending)
                     74:     {
                     75:       int i;
                     76:       struct softint_handler *current;
                     77: 
                     78:       i = ffs (pending) - 1;
                     79:       pending &= ~(1 << i);
                     80: 
                     81:       current = softint_handlers[i];
                     82:       while (current)
                     83:        {
                     84:          current->func (current->data);
                     85:          current = current->next;
                     86:        }
                     87:     }
                     88: }
                     89: 
                     90: 
                     91: /* Allocate a (well-known) software interrupt handler.  */
                     92: oskit_error_t
                     93: osenv_softirq_alloc (int irq, void (*handler)(void *), void *data, int flags)
                     94: {
                     95:   struct softint_handler *temp, **p;
                     96: 
                     97:   if (irq < 0 || irq >= SOFT_IRQ_COUNT)
                     98:     return OSKIT_EINVAL;
                     99: 
                    100:   /* Do this to ensure that the free vectors are explicitly allocated
                    101:      before having a handler assigned.  */
                    102:   if ((irq >= SOFT_IRQ_FREEBASE) && !(softint_allocated & (1 << irq)))
                    103:     return OSKIT_EINVAL;
                    104: 
                    105:   /* This is a blocking operation, so to avoid races we need to do it
                    106:      before we start mucking with data structures.  */
                    107:   temp = osenv_mem_alloc (sizeof(struct softint_handler), 0, 1);
                    108:   if (temp == NULL)
                    109:     return OSKIT_ENOMEM;
                    110:   temp->func = handler;
                    111:   temp->data = data;
                    112:   temp->next = NULL;
                    113:   temp->flags = flags;
                    114: 
                    115:   /* Note that we only hook in the new handler after its structure has been
                    116:      fully initialized;  this way we don't have to disable interrupts, because
                    117:      interrupt-level code only scans the list.  */
                    118:   for (p = &softint_handlers[irq]; *p != NULL; p = &(*p)->next)
                    119:     ;
                    120:   *p = temp;
                    121: 
                    122:   return 0;
                    123: }
                    124: 
                    125: /*  Request an unused software interrupt handler vector. This just reserves
                    126:     and returns the vector number for use with osenv_softirq_alloc() above. */
                    127: oskit_error_t
                    128: osenv_softirq_alloc_vector (int *out_irq)
                    129: {
                    130:   int i, enabled;
                    131: 
                    132:   /* Go ahead and block interrupts, cause its easy.  */
                    133:   enabled = osenv_softintr_enabled ();
                    134:   if (enabled)
                    135:     osenv_softintr_disable ();
                    136: 
                    137:   /*  Search for an empty slot above the well-known vectors.  */
                    138:   for (i = SOFT_IRQ_FREEBASE; i < SOFT_IRQ_COUNT; i++)
                    139:     {
                    140:       if (! (softint_allocated & (1 << i)))
                    141:        break;
                    142:     }
                    143:   if (i == SOFT_IRQ_COUNT)
                    144:     {
                    145:       if (enabled)
                    146:        osenv_softintr_enable ();
                    147:       return OSKIT_ERANGE;
                    148:     }
                    149: 
                    150:   softint_allocated |= (1 << i);
                    151:   *out_irq = i;
                    152: 
                    153:   if (enabled)
                    154:     osenv_softintr_enable ();
                    155:   return 0;
                    156: }
                    157: 
                    158: /* Free up a vector.  */
                    159: oskit_error_t
                    160: osenv_softirq_free_vector (int irq)
                    161: {
                    162:   /* Must be allocated */
                    163:   if (! (softint_allocated & (1 << irq)))
                    164:     return OSKIT_EINVAL;
                    165: 
                    166:   /* Must no longer be in use */
                    167:   if (softint_handlers[irq])
                    168:     return OSKIT_EINVAL;
                    169: 
                    170:   softint_allocated &= ~(1 << irq);
                    171: 
                    172:   return 0;
                    173: }
                    174: 
                    175: /* Deallocate a software interrupt.  Need a handle so know WHICH
                    176:    interrupt handler to remove.  */
                    177: void
                    178: osenv_softirq_free (int irq, void (*handler)(void *), void *data)
                    179: {
                    180:   struct softint_handler *temp, **p;
                    181: 
                    182:   osenv_assert (irq >= 0 && irq < SOFT_IRQ_COUNT);
                    183: 
                    184:   /* Find and unlink the handler from the list.  */
                    185:   p = &softint_handlers[irq];
                    186:   while (((temp = *p) != NULL)
                    187:         && (temp->func != handler || temp->data != data))
                    188:     p = &temp->next;
                    189: 
                    190:   /* not found?  */
                    191:   if (temp == NULL)
                    192:     {
                    193:       osenv_log (OSENV_LOG_WARNING,
                    194:                 "osenv_softirq_free: handler not registered!\n");
                    195:       return;
                    196:     }
                    197: 
                    198:   /* remove it!  */
                    199:   *p = temp->next;
                    200:   osenv_softintr_disable ();
                    201:   osenv_mem_free (temp, 0, sizeof(struct softint_handler));
                    202: }
                    203: 
                    204: /* Schedule a software interrupt to be delivered next time it's appropriate.
                    205:    Note that this must be called with software interrupts disabled!  */
                    206: void
                    207: osenv_softirq_schedule (int irq)
                    208: {
                    209:   osenv_assert (softint_handlers[irq]);
                    210: 
                    211:   softint_pending |= (1 << irq);
                    212:   setsoftclock ();
                    213: }
                    214: 
                    215: void
                    216: osenv_softintr_enable (void)
                    217: {
                    218:   spl_t s = osenv_softintr_spl;
                    219:   osenv_softintr_spl = SPL1;
                    220:   splx (s);
                    221: }
                    222: 
                    223: void
                    224: osenv_softintr_disable (void)
                    225: {
                    226:   /* We can be called with interrupts already disabled!  */
                    227:   if (curr_ipl > SPL1)
                    228:     /* We are already at a higher priority, so return to it.
                    229:        XXX This presumes _enable will be called at the same spl.
                    230:        Perhaps we should instead just set a flag and have
                    231:        the corresponding enable just do nothing.  */
                    232:     osenv_softintr_spl = curr_ipl;
                    233:   else if (curr_ipl < SPL1)
                    234:     /* We are at a level where software interrupts are enabled, so we must
                    235:        go to spltsoftclock.  osenv_softintr_enable we will return to the
                    236:        current level.  */
                    237:     osenv_softintr_spl = splsoftclock ();
                    238: }
                    239: 
                    240: int
                    241: osenv_softintr_enabled (void)
                    242: {
                    243:   return curr_ipl < SPL1;
                    244: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.