Annotation of OSKit-Mach/oskit/osenv_softirq.c, revision 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.