Ok, here is my first attempt. White the patch below oskit-mach should work. Unfortunately there is a (some?) bug(s). Under heavy net load oskit-mach traps after some time. Maybe someone know what I have done wrong. wagi Index: pc/osenv_timer.c =================================================================== RCS file: /cvsroot/hurd/gnumach/oskit/pc/Attic/osenv_timer.c,v retrieving revision 1.1.2.1 diff -p -c -r1.1.2.1 osenv_timer.c *** pc/osenv_timer.c 1999/11/25 23:27:56 1.1.2.1 --- pc/osenv_timer.c 2001/09/20 18:27:09 *************** *** 21,26 **** --- 21,27 ---- #include #include + #include /* base_irq_softint_* */ #include /* HZ */ #include *************** softclock_oskit (void) *** 53,59 **** osenv_intr_disable(); for (th = timer_head; th; th = th->next) (*th->func)(); ! osenv_intr_enable(); } /* --- 54,65 ---- osenv_intr_disable(); for (th = timer_head; th; th = th->next) (*th->func)(); ! ! base_irq_softint_disable (); ! softint_handler (NULL); ! base_irq_softint_enabled (); ! ! osenv_intr_enable (); } /* *** /dev/null Wed May 2 00:58:33 2001 --- osenv_softirq.c Thu Sep 20 18:01:18 2001 *************** *** 0 **** --- 1,287 ---- + /* + * Copyright (c) 2000 University of Utah and the Flux Group. + * All rights reserved. + * + * This file is part of the Flux OSKit. The OSKit is free software, also known + * as "open source;" you can redistribute it and/or modify it under the terms + * of the GNU General Public License (GPL), version 2, as published by the Free + * Software Foundation (FSF). To explore alternate licensing terms, contact + * the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271. + * + * The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have + * received a copy of the GPL along with the OSKit; see the file COPYING. If + * not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA. + */ + + /* + * Software Interrupt management. + */ + #include + #include + #include + #include + #include + #include + + #include + #include "ds_oskit.h" + + + /* linked list of functions for a software interrupt */ + struct softint_handler { + void (*func)(void *); + void *data; + struct softint_handler *next; + int flags; + }; + + /* array of pointers to lists of interrupt handlers */ + static struct softint_handler *softint_handlers[SOFT_IRQ_COUNT]; + + /* Mask of allocated vectors, for the benefit of osenv_softirq_request() */ + static unsigned int softint_allocated = + ((1 << OSENV_SOFT_IRQ_SOFTWARE) | + (1 << OSENV_SOFT_IRQ_PTHREAD)); + + /* Pending softirqs that have been software scheduled. */ + static volatile unsigned int softint_pending; + + /* + * This will override the stub function in the kernel library. It is the + * entrypoint from the hardware interrupt handler, and is invoked when + * it is safe to deliver a software interrupt, and one or more software + * interrupts is pending. + * + * Called with hardware interrupts enabled and software interrupts disabled. + * Upon return to the caller, hardware interrupts will be disabled again and + * software interrupts will be renabled. + * + * The handler will be invoked with hardware interrupts enabled. Since + * software interrupts are still disabled, if the handler results in a context + * switch, software interrupts will need to be renabled. The pthreads + * code does this in its software interrupt handler, but I think thats the + * wrong place since some other operation could result in a context switch, + * which would leave softints disabled. Perhaps there needs to be something + * in the context switch code? + * + * A software interrupt handler should obviously not allocate or deallocate + * a software interrupt. It may schedule one of course. + */ + + void + softint_handler(struct trap_state *ts) + { + osenv_intr_disable (); + + while (softint_pending) { + int i; + struct softint_handler *current; + + for (i = 0; i < SOFT_IRQ_COUNT; i++) { + if (softint_pending & (1 << i)) { + softint_pending &= ~(1 << i); + + current = softint_handlers[i]; + osenv_intr_enable (); + while (current) { + current->func(current->data); + current = current->next; + } + osenv_intr_disable (); + } + } + } + + assert (!base_irq_softint_enabled ()); + osenv_intr_enable (); + } + + + /* + * Allocate a (well-known) software interrupt handler. + */ + oskit_error_t + osenv_softirq_alloc(int irq, void (*handler)(void *), void *data, int flags) + { + struct softint_handler *temp, **p; + + if (irq < 0 || irq >= SOFT_IRQ_COUNT) + return OSKIT_EINVAL; + + /* + * Do this to ensure that the free vectors are explicitly allocated + * before having a handler assigned. + */ + if ((irq >= SOFT_IRQ_FREEBASE) && !(softint_allocated & (1 << irq))) + return OSKIT_EINVAL; + + /* + * This is a blocking operation, + * so to avoid races we need to do it + * before we start mucking with data structures. + */ + temp = osenv_mem_alloc(sizeof(struct softint_handler), 0, 1); + if (temp == NULL) + return OSKIT_ENOMEM; + temp->func = handler; + temp->data = data; + temp->next = NULL; + temp->flags = flags; + + /* Do this first */ + base_irq_softint_handler = softint_handler; + + /* + * Note that we only hook in the new handler + * after its structure has been fully initialized; + * this way we don't have to disable interrupts, + * because interrupt-level code only scans the list. + */ + for (p = &softint_handlers[irq]; *p != NULL; p = &(*p)->next) + ; + *p = temp; + + return 0; + } + + /* + * Request an unused software interrupt handler vector. This just reserves + * and returns the vector number for use with osenv_softirq_alloc() above. + */ + oskit_error_t + osenv_softirq_alloc_vector(int *out_irq) + { + int i, enabled; + + /* + * Go ahead and block interrupts, cause its easy. + */ + enabled = osenv_intr_enabled(); + if (enabled) + osenv_intr_disable(); + + /* + * Search for an empty slot above the well-known vectors. + */ + for (i = SOFT_IRQ_FREEBASE; i < SOFT_IRQ_COUNT; i++) { + if (! (softint_allocated & (1 << i))) + break; + } + if (i == SOFT_IRQ_COUNT) { + if (enabled) + osenv_intr_enable(); + return OSKIT_ERANGE; + } + + softint_allocated |= (1 << i); + *out_irq = i; + + if (enabled) + osenv_intr_enable(); + return 0; + } + + /* + * Free up a vector. + */ + oskit_error_t + osenv_softirq_free_vector(int irq) + { + /* Must be allocated */ + if (! (softint_allocated & (1 << irq))) + return OSKIT_EINVAL; + + /* Must no longer be in use */ + if (softint_handlers[irq]) + return OSKIT_EINVAL; + + softint_allocated &= ~(1 << irq); + + return 0; + } + + /* + * Deallocate a software interrupt. + * Need a handle so know WHICH interrupt handler to remove. + */ + void + osenv_softirq_free(int irq, void (*handler)(void *), void *data) + { + struct softint_handler *temp, **p; + + osenv_assert(irq >= 0 && irq < SOFT_IRQ_COUNT); + + /* + * Find and unlink the handler from the list. + */ + p = &softint_handlers[irq]; + while (((temp = *p) != NULL) && + (temp->func != handler || temp->data != data)) + p = &temp->next; + + /* not found? */ + if (temp == NULL) { + osenv_log(OSENV_LOG_WARNING, + "osenv_softirq_free: handler not registered!\n"); + return; + } + + /* remove it! */ + *p = temp->next; + base_irq_softint_disable(); + osenv_mem_free(temp, 0, sizeof(struct softint_handler)); + } + + static spl_t osenv_intr_spl; + + /* + * Schedule a software interrupt to be delivered next time its appropriate + */ + void + osenv_softirq_schedule(int irq) + { + osenv_assert(softint_handlers[irq]); + + softint_pending |= (1 << irq); + base_irq_softint_request(); + + setsoftclock (); + } + + /* + * These chain to the base_irq_softint routines. They are the equiv + * of osenv_intr_enable() and osenv_intr_disable(). + */ + extern spl_t curr_ipl; + void + osenv_softintr_enable(void) + { + spl_t s = osenv_intr_spl; + osenv_intr_spl = SPL0; + splx(s); + } + + void + osenv_softintr_disable(void) + { + /* We can be called with interrupts already disabled! */ + if (curr_ipl > SPLIO) + /* We are already at higher priority than oskit code normally runs. + I think this only happens in the calls from oskit_rtc_{get,set}. + On the assumption that osenv_intr_enable will be called in + parity from the sameqq interrupt level, we will want to stay at the + same high interrupt level. */ + osenv_intr_spl = curr_ipl; + else if (curr_ipl < SPLIO) + /* We are at a level where oskit interrupts are enabled, so we must go + to splio. osenv_intr_enable we will return to the current level. */ + osenv_intr_spl = splsoftclock (); + } + + int + osenv_softintr_enabled(void) + { + return curr_ipl < SPLIO; + }