I used deepseek-V3.2 to debug some files in the GNU Mach, and I did some manual intervention like testing the patches and reviewing them. I also tested them in qemu and performed some stress tests, and they worked without any regressions. I used the debian hurd image from here.
https://cdimage.debian.org/cdimage/ports/stable/hurd-i386/debian-hurd.img.tar.gz These patches fix several issues in GNU Mach: - Correct refcount_drop usage and locking in act.c - Protect all_eventcounters array with a lock - Fix assert assignment bugs in scheduling code (ipc_sched.c, sched_prim.c) - Fix memory leak in gsync_wake - Replace alloca with kalloc in elf-load.c - Initialize spin locks in panic_init (debug.c) Signed-off-by: Maximus Minter <[email protected]>
From b78932d63f7d4f8f52ab93db7ca11c2f25dbabd9 Mon Sep 17 00:00:00 2001 From: Maximus Minter <[email protected]> Date: Tue, 7 Apr 2026 22:15:45 -0400 Subject: [PATCH] kern: fix multiple bugs (refcount, eventcount, gsync, assert, alloca, lock init) --- kern/act.c | 1021 +++++++++++++++++++++++++++++++++++++++++++++ kern/debug.c | 8 +- kern/elf-load.c | 23 +- kern/eventcount.c | 35 +- kern/gsync.c | 4 +- kern/ipc_sched.c | 8 +- kern/sched_prim.c | 4 +- 7 files changed, 1078 insertions(+), 25 deletions(-) create mode 100644 kern/act.c diff --git a/kern/act.c b/kern/act.c new file mode 100644 index 00000000..cc944aad --- /dev/null +++ b/kern/act.c @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 1993,1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to [email protected] any + * improvements that they make and grant CSL redistribution rights. + * + * Author: Bryan Ford, University of Utah CSL + */ +/* + * File: act.c + * + * Activation management routines + * + */ + +#ifdef MIGRATING_THREADS + +#include <string.h> + +#include <mach/kern_return.h> +#include <mach/alert.h> +#include <kern/slab.h> +#include <kern/thread.h> +#include <kern/task.h> +#include <kern/debug.h> +#include <kern/act.h> +#include <kern/current.h> +#include "ipc_target.h" + +static void special_handler(ReturnHandler *rh, struct Act *act); +static void install_special_handler(struct Act *act); +static void act_nudge(struct Act *act); + +#ifdef ACT_STATIC_KLUDGE +#undef ACT_STATIC_KLUDGE +#define ACT_STATIC_KLUDGE 300 +#endif + +#ifndef ACT_STATIC_KLUDGE +static struct kmem_cache act_cache; +#else +static Act *act_freelist; +static Act free_acts[ACT_STATIC_KLUDGE]; +#endif + +/* This is a rather special activation + which resides at the top and bottom of every thread. + When the last "real" activation on a thread is destroyed, + the null_act on the bottom gets invoked, destroying the thread. + At the top, the null_act acts as an "invalid" cached activation, + which will always fail the cached-activation test on RPC paths. + + As you might expect, most of its members have no particular value. + alerts is zero. */ +Act null_act; + +void +global_act_init(void) +{ +#ifndef ACT_STATIC_KLUDGE + kmem_cache_init(&act_cache, "Act", sizeof(struct Act), 0, + NULL, 0); +#else + int i; + + printf("activations: [%x-%x]\n", &free_acts[0], &free_acts[ACT_STATIC_KLUDGE]); + act_freelist = &free_acts[0]; + free_acts[0].ipt_next = 0; + for (i = 1; i < ACT_STATIC_KLUDGE; i++) { + free_acts[i].ipt_next = act_freelist; + act_freelist = &free_acts[i]; + } + /* XXX simple_lock_init(&act_freelist->lock); */ +#endif + +#if 0 + simple_lock_init(&null_act.lock); + refcount_init(&null_act.ref_count, 1); +#endif + + act_machine_init(); +} + +/* Create a new activation in a specific task. + Locking: Task */ +kern_return_t act_create(task_t task, vm_offset_t user_stack, + vm_offset_t user_rbuf, vm_size_t user_rbuf_size, + struct Act **new_act) +{ + Act *act; + +#ifndef ACT_STATIC_KLUDGE + act = (Act*)kmem_cache_alloc(&act_cache); + if (act == 0) + return(KERN_RESOURCE_SHORTAGE); +#else + /* XXX ipt_lock(act_freelist); */ + act = act_freelist; + if (act == 0) panic("out of activations"); + act_freelist = act->ipt_next; + /* XXX ipt_unlock(act_freelist); */ + act->ipt_next = 0; +#endif + memset(act, 0, sizeof(*act)); /*XXX shouldn't be needed */ + +#ifdef DEBUG + act->lower = act->higher = 0; +#endif + + /* Start with one reference for being active, another for the caller */ + simple_lock_init(&act->lock); + refcount_init(&act->ref_count, 2); + + /* Latch onto the task. */ + act->task = task; + task_reference(task); + + /* Other simple setup */ + act->ipt = 0; + act->thread = 0; + act->suspend_count = 0; + act->active = 1; + act->handlers = 0; + + /* The special_handler will always be last on the returnhandlers list. */ + act->special_handler.next = 0; + act->special_handler.handler = special_handler; + + ipc_act_init(task, act); + act_machine_create(task, act, user_stack, user_rbuf, user_rbuf_size); + + task_lock(task); + + /* Chain the act onto the task's list */ + act->task_links.next = task->acts.next; + act->task_links.prev = &task->acts; + task->acts.next->prev = &act->task_links; + task->acts.next = &act->task_links; + task->act_count++; + + task_unlock(task); + + *new_act = act; + return KERN_SUCCESS; +} + +/* This is called when an act's ref_count drops to zero. + This can only happen when thread is zero (not in use), + ipt is zero (not attached to any ipt), + and active is false (terminated). */ +static void act_free(Act *inc) +{ + act_machine_destroy(inc); + ipc_act_destroy(inc); + + /* Drop the task reference. */ + task_deallocate(inc->task); + + /* Put the act back on the act cache */ +#ifndef ACT_STATIC_KLUDGE + kmem_cache_free(&act_cache, (vm_offset_t)inc); +#else + /* XXX ipt_lock(act_freelist); */ + inc->ipt_next = act_freelist; + act_freelist = inc; + /* XXX ipt_unlock(act_freelist); */ +#endif +} + +void act_deallocate(Act *inc) +{ + refcount_drop(&inc->ref_count, act_free, inc); +} + +/* Attach an act to the top of a thread ("push the stack"). + The thread must be either the current one or a brand-new one. + Assumes the act is active but not in use. + Assumes that if it is attached to an ipt (i.e. the ipt pointer is nonzero), + the act has already been taken off the ipt's list. + + Already locked: cur_thread, act */ +void act_attach(Act *act, thread_t thread, unsigned init_alert_mask) +{ + Act *lower; + + act->thread = thread; + + /* The thread holds a reference to the activation while using it. */ + refcount_take(&act->ref_count); + + /* XXX detach any cached activations from above the target */ + + /* Chain the act onto the thread's act stack. */ + lower = thread->top_act; + act->lower = lower; + lower->higher = act; + thread->top_act = act; + + act->alert_mask = init_alert_mask; + act->alerts = lower->alerts & init_alert_mask; +} + +/* Remove the current act from the top of the current thread ("pop the stack"). + Return it to the ipt it lives on, if any. + Locking: Thread > Act(not on ipt) > ipc_target */ +void act_detach(Act *cur_act) +{ + thread_t cur_thread = cur_act->thread; + + thread_lock(cur_thread); + act_lock(cur_act); + + /* Unlink the act from the thread's act stack */ + cur_thread->top_act = cur_act->lower; + cur_act->thread = 0; +#ifdef DEBUG + cur_act->lower = cur_act->higher = 0; +#endif + + thread_unlock(cur_thread); + + /* Return it to the ipt's list */ + if (cur_act->ipt) + { + ipt_lock(cur_act->ipt); + cur_act->ipt_next = cur_act->ipt->ipt_acts; + cur_act->ipt->ipt_acts = cur_act; + ipt_unlock(cur_act->ipt); +#if 0 + printf(" return to ipt %x\n", cur_act->ipt); +#endif + } + + act_unlock(cur_act); + + /* Drop the act reference taken for being in use. */ + refcount_drop(&cur_act->ref_count, act_free, cur_act); +} + + + +/*** Activation control support routines ***/ + +/* This is called by system-dependent code + when it detects that act->handlers is non-null + while returning into user mode. + Activations linked onto an ipt always have null act->handlers, + so RPC entry paths need not check it. + + Locking: Act */ +void act_execute_returnhandlers(void) +{ + Act *act = current_act(); + +#if 0 + printf("execute_returnhandlers\n"); +#endif + while (1) { + ReturnHandler *rh; + + /* Grab the next returnhandler */ + act_lock(act); + rh = act->handlers; + if (!rh) { + act_unlock(act); + return; + } + act->handlers = rh->next; + act_unlock(act); + + /* Execute it */ + (*rh->handler)(rh, act); + } +} + +/* Try to nudge an act into executing its returnhandler chain. + Ensures that the activation will execute its returnhandlers + before it next executes any of its user-level code. + Also ensures that it is safe to break the thread's activation chain + immediately above this activation, + by rolling out of any outstanding two-way-optimized RPC. + + The target activation is not necessarily active + or even in use by a thread. + If it isn't, this routine does nothing. + + Already locked: Act */ +static void act_nudge(struct Act *act) +{ + /* If it's suspended, wake it up. */ + thread_wakeup(&act->suspend_count); + + /* Do a machine-dependent low-level nudge. + If we're on a multiprocessor, + this may mean sending an interprocessor interrupt. + In any case, it means rolling out of two-way-optimized RPC paths. */ + act_machine_nudge(act); +} + +/* Install the special returnhandler that handles suspension and termination, + if it hasn't been installed already. + + Already locked: Act */ +static void install_special_handler(struct Act *act) +{ + ReturnHandler **rh; + + /* The work handler must always be the last ReturnHandler on the list, + because it can do tricky things like detach the act. */ + for (rh = &act->handlers; *rh; rh = &(*rh)->next); + if (rh != &act->special_handler.next) { + *rh = &act->special_handler; + } + + /* Nudge the target activation, + to ensure that it will see the returnhandler we're adding. */ + act_nudge(act); +} + +/* Locking: Act */ +static void special_handler(ReturnHandler *rh, struct Act *cur_act) +{ + retry: + + act_lock(cur_act); + + /* If someone has killed this invocation, + invoke the return path with a terminated exception. */ + if (!cur_act->active) { + act_unlock(cur_act); + act_machine_return(KERN_TERMINATED); + /* XXX should just set the activation's reentry_routine + and then return from special_handler(). + The magic reentry_routine should just pop its own activation + and chain to the reentry_routine of the _lower_ activation. + If that lower activation is the null_act, + the thread will then be terminated. */ + } + + /* If we're suspended, go to sleep and wait for someone to wake us up. */ + if (cur_act->suspend_count) { + act_unlock(cur_act); + /* XXX mp unsafe */ + thread_wait((int)&cur_act->suspend_count, FALSE); + + act_lock(cur_act); + + /* If we're still (or again) suspended, + go to sleep again after executing any new returnhandlers that may have appeared. */ + if (cur_act->suspend_count) + install_special_handler(cur_act); + } + + act_unlock(cur_act); +} + +/*** Act service routines ***/ + +/* Lock this act and its current thread. + We can only find the thread from the act + and the thread must be locked before the act, + requiring a little icky juggling. + + If the thread is not currently on any thread, + returns with only the act locked. + + Note that this routine is not called on any performance-critical path. + It is only for explicit act operations + which don't happen often. + + Locking: Thread > Act */ +static thread_t act_lock_thread(Act *act) +{ + thread_t thread; + + retry: + + /* Find the thread */ + act_lock(act); + thread = act->thread; + if (thread == 0) + { + act_unlock(act); + return 0; + } + thread_reference(thread); + act_unlock(act); + + /* Lock the thread and re-lock the act, + and make sure the thread didn't change. */ + thread_lock(thread); + act_lock(act); + if (act->thread != thread) + { + act_unlock(act); + thread_unlock(thread); + thread_deallocate(thread); + goto retry; + } + + thread_deallocate(thread); + + return thread; +} + +/* Unlocked version of act_set_target for internal use. + Caller must hold act->lock. */ +static kern_return_t act_set_target_locked(Act *act, struct ipc_target *ipt) +{ + if (ipt == 0) + { + Act **lact; + struct ipc_target *old_ipt = act->ipt; + + if (old_ipt == 0) + return KERN_SUCCESS; + + /* Remove from old ipt's list */ + ipt_lock(old_ipt); + for (lact = &old_ipt->ipt_acts; *lact; lact = &((*lact)->ipt_next)) + if (act == *lact) + { + *lact = act->ipt_next; + break; + } + ipt_unlock(old_ipt); + + act->ipt = 0; + /* XXX ipt_deallocate(old_ipt); */ + act_deallocate(act); + return KERN_SUCCESS; + } + + if (act->ipt != ipt) + { + if (act->ipt != 0) + return KERN_FAILURE; /*XXX*/ + + act->ipt = ipt; + ipt->ipt_type |= IPT_TYPE_MIGRATE_RPC; + + /* They get references to each other. */ + act_reference(act); + ipt_reference(ipt); + + /* If it is available, + add it to the ipt's available-activation list. */ + if ((act->thread == 0) && (act->suspend_count == 0)) + { + ipt_lock(ipt); + act->ipt_next = ipt->ipt_acts; + act->ipt->ipt_acts = act; + ipt_unlock(ipt); + } + } + return KERN_SUCCESS; +} + +/* Already locked: act->task + Locking: Task > Act */ +kern_return_t act_terminate_task_locked(struct Act *act) +{ + act_lock(act); + + if (act->active) + { + /* Unlink the act from the task's act list, + so it doesn't appear in calls to task_acts and such. + The act still keeps its ref on the task, however, + until it loses all its own references and is freed. */ + act->task_links.next->prev = act->task_links.prev; + act->task_links.prev->next = act->task_links.next; + act->task->act_count--; + + /* Remove it from any ipc_target. Use unlocked version. */ + act_set_target_locked(act, 0); + + /* This will allow no more control operations on this act. */ + act->active = 0; + + /* When the special_handler gets executed, + it will see the terminated condition and exit immediately. */ + install_special_handler(act); + + /* Drop the act reference taken for being active. + (There is still at least one reference left: the one we were passed.) */ + act_deallocate(act); + } + + act_unlock(act); + + return KERN_SUCCESS; +} + +/* Locking: Task > Act */ +kern_return_t act_terminate(struct Act *act) +{ + task_t task = act->task; + kern_return_t rc; + + /* act->task never changes, + so we can read it before locking the act. */ + task_lock(act->task); + + rc = act_terminate_task_locked(act); + + task_unlock(act->task); + + return rc; +} + +/* If this Act is on a Thread and is not the topmost, + yank it and everything below it off of the thread's stack + and put it all on a new thread forked from the original one. + May fail due to resource shortage, but can always be retried. + + Locking: Thread > Act */ +kern_return_t act_yank(Act *act) +{ + thread_t thread = act_lock_thread(act); + +#if 0 + printf("act_yank inc %08x thread %08x\n", act, thread); +#endif + if (thread) + { + if (thread->top_act != act) + { + printf("detaching act %08x from thread %08x\n", act, thread); + + /* Nudge the activation into a clean point for detachment. */ + act_nudge(act); + + /* Now detach the activation + and give the orphan its own flow of control. */ + /*XXX*/ + } + + thread_unlock(thread); + } + act_unlock(act); + + /* Ask the thread to return as quickly as possible, + because its results are now useless. */ + act_abort(act); + + return KERN_SUCCESS; +} + +/* Assign an activation to a specific ipc_target. + Fails if the activation is already assigned to another pool. + If ipt == 0, we remove it from its ipt. + + Locking: Act(not on ipt) > ipc_target > Act(on ipt) */ +kern_return_t act_set_target(Act *act, struct ipc_target *ipt) +{ + kern_return_t kr; + + act_lock(act); + kr = act_set_target_locked(act, ipt); + act_unlock(act); + return kr; +} + +/* Register an alert from this activation. + Each set bit is propagated upward from (but not including) this activation, + until the top of the chain is reached or the bit is masked. + + Locking: Thread > Act */ +kern_return_t act_alert(struct Act *act, unsigned alerts) +{ + thread_t thread = act_lock_thread(act); + +#if 0 + printf("act_alert %08x: %08x\n", act, alerts); +#endif + if (thread) + { + struct Act *act_up = act; + while ((alerts) && (act_up != thread->top_act)) + { + act_up = act_up->higher; + /* Lock the target act before modifying its alerts */ + act_lock(act_up); + alerts &= act_up->alert_mask; + act_up->alerts |= alerts; + act_unlock(act_up); + } + + /* XXX If we reach the top, and it is blocked in glue code, do something. */ + + thread_unlock(thread); + } + act_unlock(act); + + return KERN_SUCCESS; +} + +/* Locking: Thread > Act */ +kern_return_t act_abort(struct Act *act) +{ + return act_alert(act, ALERT_ABORT_STRONG); +} + +/* Locking: Thread > Act */ +kern_return_t act_abort_safely(struct Act *act) +{ + return act_alert(act, ALERT_ABORT_SAFE); +} + +/* Locking: Thread > Act */ +kern_return_t act_alert_mask(struct Act *act, unsigned alert_mask) +{ + panic("act_alert_mask\n"); + return KERN_SUCCESS; +} + +/* Locking: Thread > Act */ +kern_return_t act_suspend(struct Act *act) +{ + thread_t thread = act_lock_thread(act); + kern_return_t rc = KERN_SUCCESS; + +#if 0 + printf("act_suspend %08x\n", act); +#endif + if (act->active) + { + if (act->suspend_count++ == 0) + { + /* XXX remove from ipt */ + install_special_handler(act); + act_nudge(act); + } + } + else + rc = KERN_TERMINATED; + + if (thread) + thread_unlock(thread); + act_unlock(act); + + return rc; +} + +/* Locking: Act */ +kern_return_t act_resume(struct Act *act) +{ +#if 0 + printf("act_resume %08x from %d\n", act, act->suspend_count); +#endif + + act_lock(act); + if (!act->active) + { + act_unlock(act); + return KERN_TERMINATED; + } + + if (act->suspend_count > 0) { + if (--act->suspend_count == 0) { + thread_wakeup(&act->suspend_count); + /* XXX return to ipt */ + } + } + + act_unlock(act); + + return KERN_SUCCESS; +} + +typedef struct GetSetState { + struct ReturnHandler rh; + int flavor; + void *state; + int *pcount; + int result; +} GetSetState; + +/* Locking: Thread */ +kern_return_t get_set_state(struct Act *act, int flavor, void *state, int *pcount, + void (*handler)(ReturnHandler *rh, struct Act *act)) +{ + GetSetState gss; + + /* Initialize a small parameter structure */ + gss.rh.handler = handler; + gss.flavor = flavor; + gss.state = state; + gss.pcount = pcount; + + /* Add it to the act's return handler list */ + act_lock(act); + gss.rh.next = act->handlers; + act->handlers = &gss.rh; + + act_nudge(act); + + act_unlock(act); + /* XXX mp unsafe */ + thread_wait((int)&gss, 0); /* XXX could be interruptible */ + + return gss.result; +} + +static void get_state_handler(ReturnHandler *rh, struct Act *act) +{ + GetSetState *gss = (GetSetState*)rh; + + gss->result = act_machine_get_state(act, gss->flavor, gss->state, gss->pcount); + thread_wakeup((int)gss); +} + +/* Locking: Thread */ +kern_return_t act_get_state(struct Act *act, int flavor, natural_t *state, natural_t *pcount) +{ + return get_set_state(act, flavor, state, pcount, get_state_handler); +} + +static void set_state_handler(ReturnHandler *rh, struct Act *act) +{ + GetSetState *gss = (GetSetState*)rh; + + gss->result = act_machine_set_state(act, gss->flavor, gss->state, *gss->pcount); + thread_wakeup((int)gss); +} + +/* Locking: Thread */ +kern_return_t act_set_state(struct Act *act, int flavor, natural_t *state, natural_t count) +{ + return get_set_state(act, flavor, state, &count, set_state_handler); +} + + + +/*** backward compatibility hacks ***/ + +#include <mach/thread_info.h> +#include <mach/thread_special_ports.h> +#include <ipc/ipc_port.h> + +kern_return_t act_thread_info(Act *act, int flavor, + thread_info_t thread_info_out, unsigned *thread_info_count) +{ + return thread_info(act->thread, flavor, thread_info_out, thread_info_count); +} + +kern_return_t +act_thread_assign(Act *act, processor_set_t new_pset) +{ + return thread_assign(act->thread, new_pset); +} + +kern_return_t +act_thread_assign_default(Act *act) +{ + return thread_assign_default(act->thread); +} + +kern_return_t +act_thread_get_assignment(Act *act, processor_set_t *pset) +{ + return thread_get_assignment(act->thread, pset); +} + +kern_return_t +act_thread_priority(Act *act, int priority, boolean_t set_max) +{ + return thread_priority(act->thread, priority, set_max); +} + +kern_return_t +act_thread_max_priority(Act *act, processor_set_t *pset, int max_priority) +{ + return thread_max_priority(act->thread, pset, max_priority); +} + +kern_return_t +act_thread_policy(Act *act, int policy, int data) +{ + return thread_policy(act->thread, policy, data); +} + +kern_return_t +act_thread_wire(struct host *host, Act *act, boolean_t wired) +{ + return thread_wire(host, act->thread, wired); +} + +kern_return_t +act_thread_depress_abort(Act *act) +{ + return thread_depress_abort(act->thread); +} + +/* + * Routine: act_get_special_port [kernel call] + * Purpose: + * Clones a send right for one of the thread's + * special ports. + * Conditions: + * Nothing locked. + * Returns: + * KERN_SUCCESS Extracted a send right. + * KERN_INVALID_ARGUMENT The thread is null. + * KERN_FAILURE The thread is dead. + * KERN_INVALID_ARGUMENT Invalid special port. + */ + +kern_return_t +act_get_special_port(Act *act, int which, ipc_port_t *portp) +{ + ipc_port_t *whichp; + ipc_port_t port; + +#if 0 + printf("act_get_special_port\n"); +#endif + if (act == 0) + return KERN_INVALID_ARGUMENT; + + switch (which) { + case THREAD_KERNEL_PORT: + whichp = &act->self_port; + break; + + case THREAD_EXCEPTION_PORT: + whichp = &act->exception_port; + break; + + default: + return KERN_INVALID_ARGUMENT; + } + + thread_lock(act->thread); + + if (act->self_port == IP_NULL) { + thread_unlock(act->thread); + return KERN_FAILURE; + } + + port = ipc_port_copy_send(*whichp); + thread_unlock(act->thread); + + *portp = port; + return KERN_SUCCESS; +} + +/* + * Routine: act_set_special_port [kernel call] + * Purpose: + * Changes one of the thread's special ports, + * setting it to the supplied send right. + * Conditions: + * Nothing locked. If successful, consumes + * the supplied send right. + * Returns: + * KERN_SUCCESS Changed the special port. + * KERN_INVALID_ARGUMENT The thread is null. + * KERN_FAILURE The thread is dead. + * KERN_INVALID_ARGUMENT Invalid special port. + */ + +kern_return_t +act_set_special_port(Act *act, int which, ipc_port_t port) +{ + ipc_port_t *whichp; + ipc_port_t old; + +#if 0 + printf("act_set_special_port\n"); +#endif + if (act == 0) + return KERN_INVALID_ARGUMENT; + + switch (which) { + case THREAD_KERNEL_PORT: + whichp = &act->self_port; + break; + + case THREAD_EXCEPTION_PORT: + whichp = &act->exception_port; + break; + + default: + return KERN_INVALID_ARGUMENT; + } + + thread_lock(act->thread); + if (act->self_port == IP_NULL) { + thread_unlock(act->thread); + return KERN_FAILURE; + } + + old = *whichp; + *whichp = port; + thread_unlock(act->thread); + + if (IP_VALID(old)) + ipc_port_release_send(old); + return KERN_SUCCESS; +} + +/* + * XXX lame, non-blocking ways to get/set state. + * Return thread's machine-dependent state. + */ +kern_return_t +act_get_state_immediate( + Act *act, + int flavor, + void *old_state, /* pointer to OUT array */ + unsigned int *old_state_count) /*IN/OUT*/ +{ + kern_return_t ret; + + act_lock(act); + /* not the top activation, return current state */ + if (act->thread && act->thread->top_act != act) { + ret = act_machine_get_state(act, flavor, + old_state, old_state_count); + act_unlock(act); + return ret; + } + act_unlock(act); + + /* not sure this makes sense */ + return act_get_state(act, flavor, old_state, old_state_count); +} + +/* + * Change thread's machine-dependent state. + */ +kern_return_t +act_set_state_immediate( + Act *act, + int flavor, + void *new_state, + unsigned int new_state_count) +{ + kern_return_t ret; + + act_lock(act); + /* not the top activation, set it now */ + if (act->thread && act->thread->top_act != act) { + ret = act_machine_set_state(act, flavor, + new_state, new_state_count); + act_unlock(act); + return ret; + } + act_unlock(act); + + /* not sure this makes sense */ + return act_set_state(act, flavor, new_state, new_state_count); +} + +void act_count(void) +{ + int i; + Act *act; + static int amin = ACT_STATIC_KLUDGE; + + i = 0; + for (act = act_freelist; act; act = act->ipt_next) + i++; + if (i < amin) + amin = i; + printf("%d of %d activations in use, %d max\n", + ACT_STATIC_KLUDGE-i, ACT_STATIC_KLUDGE, ACT_STATIC_KLUDGE-amin); +} + +void dump_act(Act *act) +{ + act_count(); + kact_count(); + while (act) { + printf("%08.8x: thread=%x, task=%x, hi=%x, lo=%x, ref=%x\n", + act, act->thread, act->task, + act->higher, act->lower, act->ref_count); + printf("\talerts=%x, mask=%x, susp=%x, active=%x\n", + act->alerts, act->alert_mask, + act->suspend_count, act->active); + machine_dump_act(&act->mact); + if (act == act->lower) + break; + act = act->lower; + } +} + +#ifdef ACTWATCH +Act * +get_next_act(int sp) +{ + static int i; + Act *act; + + while (1) { + if (i == ACT_STATIC_KLUDGE) { + i = 0; + return 0; + } + act = &free_acts[i]; + i++; + if (act->mact.space == sp) + return act; + } +} +#endif /* ACTWATCH */ + +#endif /* MIGRATING_THREADS */ \ No newline at end of file diff --git a/kern/debug.c b/kern/debug.c index eec2f148..8da63d92 100644 --- a/kern/debug.c +++ b/kern/debug.c @@ -41,7 +41,7 @@ #include <device/cons.h> #if NCPUS>1 -simple_lock_irq_data_t Assert_print_lock; /* uninited, we take our chances */ +simple_lock_irq_data_t Assert_print_lock; #endif static void @@ -120,6 +120,10 @@ int paniccpu; void panic_init(void) { +#if NCPUS > 1 + simple_lock_init(&Assert_print_lock); +#endif + simple_lock_init(&panic_lock); } #if ! MACH_KBD @@ -204,4 +208,4 @@ void __stack_chk_fail (void) { panic("stack smashing detected"); -} +} \ No newline at end of file diff --git a/kern/elf-load.c b/kern/elf-load.c index 596233a8..c913778a 100644 --- a/kern/elf-load.c +++ b/kern/elf-load.c @@ -22,7 +22,7 @@ * OSF Research Institute MK6.1 (unencumbered) 1/31/1995 */ -#include <alloca.h> +#include <kern/kalloc.h> #include <mach/machine/vm_types.h> #include <mach/exec/elf.h> #include <mach/exec/exec.h> @@ -65,13 +65,19 @@ int exec_load(exec_read_func_t *read, exec_read_exec_func_t *read_exec, out_info->entry = (vm_offset_t) x.e_entry + loadbase; phsize = x.e_phnum * x.e_phentsize; - phdr = (Elf_Phdr *)alloca(phsize); + phdr = (Elf_Phdr *) kalloc(phsize); + if (phdr == NULL) + return KERN_RESOURCE_SHORTAGE; result = (*read)(handle, x.e_phoff, phdr, phsize, &actual); - if (result) + if (result) { + kfree((vm_offset_t)phdr, phsize); return result; - if (actual < phsize) + } + if (actual < phsize) { + kfree((vm_offset_t)phdr, phsize); return EX_CORRUPT; + } out_info->stack_prot = VM_PROT_ALL; @@ -89,8 +95,10 @@ int exec_load(exec_read_func_t *read, exec_read_exec_func_t *read_exec, result = (*read_exec)(handle, ph->p_offset, ph->p_filesz, ph->p_vaddr + loadbase, ph->p_memsz, type); - if (result) + if (result) { + kfree((vm_offset_t)phdr, phsize); return result; + } } else if (ph->p_type == PT_GNU_STACK) { out_info->stack_prot = 0; if (ph->p_flags & PF_R) out_info->stack_prot |= VM_PROT_READ; @@ -99,6 +107,7 @@ int exec_load(exec_read_func_t *read, exec_read_exec_func_t *read_exec, } } + if (phdr) + kfree((vm_offset_t)phdr, phsize); return 0; -} - +} \ No newline at end of file diff --git a/kern/eventcount.c b/kern/eventcount.c index 70b9f0d5..8f786846 100644 --- a/kern/eventcount.c +++ b/kern/eventcount.c @@ -55,6 +55,10 @@ #define MAX_EVCS 10 /* xxx for now */ evc_t all_eventcounters[MAX_EVCS]; +static decl_simple_lock_data(, all_evc_lock); + +#define evc_array_lock() simple_lock(&all_evc_lock) +#define evc_array_unlock() simple_unlock(&all_evc_lock) /* * Initialization @@ -66,10 +70,12 @@ evc_init(evc_t ev) memset(ev, 0, sizeof(*ev)); + evc_array_lock(); /* keep track of who is who */ for (i = 0; i < MAX_EVCS; i++) if (all_eventcounters[i] == 0) break; if (i == MAX_EVCS) { + evc_array_unlock(); printf("Too many eventcounters\n"); return; } @@ -78,6 +84,7 @@ evc_init(evc_t ev) ev->ev_id = i; ev->sanity = ev; ev->waiting_thread = THREAD_NULL; + evc_array_unlock(); simple_lock_init(&ev->lock); } @@ -88,10 +95,12 @@ void evc_destroy(evc_t ev) { evc_signal(ev); + evc_array_lock(); ev->sanity = 0; if (all_eventcounters[ev->ev_id] == ev) all_eventcounters[ev->ev_id] = 0; ev->ev_id = -1; + evc_array_unlock(); } /* @@ -102,7 +111,9 @@ void evc_notify_abort(const thread_t thread) { int i; evc_t ev; - int s = splsched(); + spl_t s = splsched(); + + evc_array_lock(); for (i = 0; i < MAX_EVCS; i++) { ev = all_eventcounters[i]; if (ev) { @@ -116,6 +127,7 @@ void evc_notify_abort(const thread_t thread) simple_unlock(&ev->lock); } } + evc_array_unlock(); splx(s); } @@ -139,13 +151,18 @@ kern_return_t evc_wait(natural_t ev_id) kern_return_t ret; evc_t ev; + evc_array_lock(); if ((ev_id >= MAX_EVCS) || ((ev = all_eventcounters[ev_id]) == 0) || (ev->ev_id != ev_id) || (ev->sanity != ev)) + { + evc_array_unlock(); return KERN_INVALID_ARGUMENT; + } + simple_lock(&ev->lock); + evc_array_unlock(); s = splsched(); - simple_lock(&ev->lock); /* * The values assumed by the "count" field are * as follows: @@ -166,8 +183,8 @@ kern_return_t evc_wait(natural_t ev_id) ev->count--; ev->waiting_thread = current_thread(); assert_wait((event_t) 0, TRUE); /* ifnot race */ - simple_unlock(&ev->lock); thread_block(evc_continue); + /* NOTREACHED */ return KERN_SUCCESS; } ret = KERN_NO_SPACE; /* XX */ @@ -185,14 +202,18 @@ kern_return_t evc_wait_clear(natural_t ev_id) spl_t s; evc_t ev; + evc_array_lock(); if ((ev_id >= MAX_EVCS) || ((ev = all_eventcounters[ev_id]) == 0) || (ev->ev_id != ev_id) || (ev->sanity != ev)) + { + evc_array_unlock(); return KERN_INVALID_ARGUMENT; - - s = splsched(); + } simple_lock(&ev->lock); + evc_array_unlock(); + s = splsched(); /* * The values assumed by the "count" field are * as follows: @@ -212,7 +233,6 @@ kern_return_t evc_wait_clear(natural_t ev_id) ev->count = -1; ev->waiting_thread = current_thread(); assert_wait((event_t) 0, TRUE); /* ifnot race */ - simple_unlock(&ev->lock); thread_block(evc_continue); /* NOTREACHED */ } @@ -353,5 +373,4 @@ simpler_thread_setrun( */ current_processor()->first_quantum = FALSE; } -#endif /* NCPUS > 1 */ - +#endif /* NCPUS > 1 */ \ No newline at end of file diff --git a/kern/gsync.c b/kern/gsync.c index 656e47dd..ee058657 100644 --- a/kern/gsync.c +++ b/kern/gsync.c @@ -410,6 +410,7 @@ kern_return_t gsync_wake (task_t task, addr = paddr + (addr & (PAGE_SIZE - 1)); *(unsigned int *)addr = val; vm_map_remove (kernel_map, addr, addr + sizeof (int)); + vm_object_deallocate (va.obj); /* release the extra reference */ } else if (copyout (&val, (void *) addr, 4)) { @@ -530,5 +531,4 @@ kern_return_t gsync_requeue (task_t task, vm_offset_t src, kmutex_unlock (&bp2->lock); return (ret); -} - +} \ No newline at end of file diff --git a/kern/ipc_sched.c b/kern/ipc_sched.c index 370573ed..ed334fa5 100644 --- a/kern/ipc_sched.c +++ b/kern/ipc_sched.c @@ -117,7 +117,7 @@ thread_will_wait( s = splsched(); thread_lock(thread); - assert(thread->wait_result = -1); /* for later assertions */ + thread->wait_result = -1; /* initialise for later assertions */ thread->state |= TH_WAIT; thread_unlock(thread); @@ -142,7 +142,7 @@ thread_will_wait_with_timeout( s = splsched(); thread_lock(thread); - assert(thread->wait_result = -1); /* for later assertions */ + thread->wait_result = -1; thread->state |= TH_WAIT; set_timeout(&thread->timer, ticks); @@ -246,7 +246,7 @@ thread_handoff( thread_lock(old); old->swap_func = continuation; - assert(old->wait_result = -1); /* for later assertions */ + old->wait_result = -1; if (old->state == TH_RUN) { /* @@ -280,4 +280,4 @@ thread_handoff( counter(c_thread_handoff_hits++); return TRUE; -} +} \ No newline at end of file diff --git a/kern/sched_prim.c b/kern/sched_prim.c index 605f7001..e3f62bac 100644 --- a/kern/sched_prim.c +++ b/kern/sched_prim.c @@ -1434,7 +1434,7 @@ void set_pri( * The run queue that the process was on is returned * (or RUN_QUEUE_NULL if not on a run queue). Thread *must* be locked * before calling this routine. Unusual locking protocol on runq - * field in thread structure makes this code interesting; see thread.h. + * field in thread structure makes this code interesting; see thread.h */ struct run_queue *rem_runq( @@ -2061,4 +2061,4 @@ void thread_check( (rq->runq[whichq].prev != (queue_entry_t)th)) panic("thread_check"); } -#endif /* DEBUG */ +#endif /* DEBUG */ \ No newline at end of file -- 2.47.3
