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: Your 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

Reply via email to