📄 bjthread.c
字号:
/* * Copyright (c) 1998 The University of Utah. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file. * * Contributed by the Flux Research Group at the University of Utah. * Authors: Godmar Back, Leigh Stoller *//* * This file implements jthreads on top of BeOS native threads and * was derived from oskit-pthreads/pjthread.c. * * Please address BeOS-related questions to alanlb@vt.edu. */#include "debug.h"#include "jthread.h"#include <sys/wait.h>#include <sys/time.h>#include <signal.h>/* thread status */#define THREAD_NEWBORN 0#define THREAD_RUNNING 1#define THREAD_DYING 2#define THREAD_DEAD 3/* * We use this as a stop signal instead of SIGSTOP, because an apparent * bug in R4 prevents a custom SIGSTOP handler from ever being called. */#define STOP_SIGNAL SIGUSR2/* * Variables. * These should be kept static to ensure encapsulation. */static int talive; /* number of threads alive */static int tdaemon; /* number of daemons alive */static void (*runOnExit)(void); /* run when all non-daemons die */static struct jthread* liveThreads; /* list of all live threads */static sem_id threadLock; /* static lock to protect liveThreads */static int map_Java_priority(int jprio);static void remove_thread(jthread_t tid);static void mark_thread_dead(void);void dumpLiveThreads(int);static void deathcallback(int sig); /* runs when STOPped and stop is OK *//* * the following variables are set by jthread_init, and show how the * threading system is parameterized. */static void *(*allocator)(size_t); /* malloc */static void (*deallocator)(void*); /* free */static void (*destructor1)(void*); /* call when a thread exits */static void (*onstop)(void); /* call when a thread is stopped */static int max_priority; /* maximum supported priority */static int min_priority; /* minimum supported priority *//* * This is used to track the id of the main thread, so that we can * prevent it from exiting while there are daemon threads still * running. otherwise, the environ ptr would become invalid, and * any remaining non-daemon thread that called getenv() either directly * or indirectly via, say, gethostbyname(), would fail with a * NullPointerException. * * This scenario revealed itself with the UDPTest program in the * regression suite. */static thread_id the_main_thread;/* * This is where the cookies are kept */per_thread_info_t* per_thread_info;static area_id pti_area;/* * This is used to prevent multiple STOP_SIGNALs from being sent to the * daemon threads during final shutdown. */static int32 isShuttingDown = 0;/* * Helpers */#define THREAD_NAME(jtid) nameThread(jtid->jlThread)/*============================================================================ * * Functions related to interrupt handling * *//* * Suspend all threads */void jthread_suspendall(void){ /* Unimplemented */}/* * Unsuspend all threads */voidjthread_unsuspendall(void){ /* Unimplemented */}/* * acquire spinlock */void jthread_spinon(void *arg){ int32* lock = arg; int32 prev; if (NULL != lock) { do { prev = atomic_or(lock, 1); } while (1 == prev); }}/* * release spinlock */void jthread_spinoff(void *arg){ int32* lock = arg; if (NULL != lock) { atomic_and(lock, 0); }}/*============================================================================ * * Functions related to the stack * *//* * determine the interesting stack range for a conservative gc */intjthread_extract_stack(jthread_t jtid, void **from, unsigned *len){ if (NULL == jtid) { return(0); } *from = jtid->stack_bottom; *len = jtid->stack_top - jtid->stack_bottom; return(1);}/* * determine whether an address lies on your current stack frame */intjthread_on_current_stack(void *bp){ int dummy = 0; jthread_t currentJThread = GET_JTHREAD(); return(bp >= (void*)&dummy && bp < currentJThread->stack_top);} /* * See if there is enough room on the stack. */intjthread_stackcheck(int need){ int dummy = 0; if (0 == need) { return(1); } else { jthread_t currentJThread = GET_JTHREAD(); return(((void*)&dummy - currentJThread->stack_bottom) >= need); }}/*============================================================================ * * Functions dealing with thread contexts and the garbage collection interface * *//* * free a thread context */void jthread_destroy(jthread_t tid){ status_t status; assert(tid); DBG(JTHREAD, dprintf("destroying %s\n", THREAD_NAME(tid));) atomic_and(&tid->stop_allowed, 0); wait_for_thread(tid->native_thread, &status); atomic_or(&tid->stop_allowed, 1); deallocator(tid);}/* * find a native BeOS thread's cookie * (Maps BeOS threads to java.lang.Threads) *//*void* jthread_getcookie(void* ntid){ struct jthread* tid; for (tid = liveThreads; tid != NULL; tid = tid->nextlive) { if ((void*)tid->native_thread == ntid) { return (tid->jlThread); } } return (0);}*//* * iterate over all live threads */voidjthread_walkLiveThreads(void (*func)(void *jlThread)){ jthread_t tid; acquire_sem(threadLock); for (tid = liveThreads; tid != NULL; tid = tid->nextlive) { func(tid->jlThread); } release_sem(threadLock);}/* * XXX this is supposed to count the number of stack frames */intjthread_frames(jthread_t thrd){ return 0;}/*============================================================================ * * Functions for initialization and thread creation * */static intmap_Java_priority(int prio){ double range = max_priority - min_priority; double diff = prio - min_priority; if (0 == range) { return(B_NORMAL_PRIORITY); } else { return(B_LOW_PRIORITY + (double)(B_URGENT_DISPLAY_PRIORITY-B_LOW_PRIORITY) * (diff / range)); }}/* * Initialize the threading system. */jthread_t jthread_init( int preemptive, int maxpr, int minpr, void *(*_allocator)(size_t), void (*_deallocator)(void*), void (*_destructor1)(void*), void (*_onstop)(void), void (*_ondeadlock)(void)) /* ignored for now */{ thread_id pmain; jthread_t jtid; void* pti_addr; thread_info tinfo; max_priority = maxpr; min_priority = minpr; allocator = _allocator; deallocator = _deallocator; onstop = _onstop; destructor1 = _destructor1; /* * Prepare the area used for the cookies, etc. */ pti_area = create_area("Kaffe cookies", &pti_addr, B_ANY_ADDRESS, PTI_AREA_SIZE, B_LAZY_LOCK, B_READ_AREA|B_WRITE_AREA); assert(pti_area >= B_OK); memset(pti_addr, PTI_AREA_SIZE, 0); per_thread_info = (per_thread_info_t*)pti_addr; threadLock = create_sem(1, "Kaffe threadLock"); pmain = find_thread(NULL); rename_thread(pmain, "Kaffe main thread"); /* * Record the id of the main thread, for use by jthread_exit */ the_main_thread = pmain; jtid = allocator(sizeof (*jtid)); SET_JTHREAD(jtid); jtid->native_thread = pmain; /* * Determine the top and bottom addrs of this thread's stack */ get_thread_info(pmain, &tinfo); jtid->stack_top = tinfo.stack_end; jtid->stack_bottom = tinfo.stack_base; /* * In case of unnatural death (induced by receiving a STOP_SIGNAL), * we install the appropriate signal handler. */ signal(STOP_SIGNAL, deathcallback); jtid->stop_allowed = 1; jtid->stop_pending = 0; jtid->nextlive = liveThreads; liveThreads = jtid; jtid->status = THREAD_RUNNING; talive++; DBG(JTHREAD, dprintf("main thread has id %x\n", jtid->native_thread);) return (jtid);}/* * Create the first thread - actually bind the first thread to the java * context. */jthread_tjthread_createfirst(size_t mainThreadStackSize, unsigned char prio, void* jlThread){ jthread_t jtid; jtid = GET_JTHREAD(); assert(jtid != NULL); assert(jtid->native_thread != 0); assert(jtid->status == THREAD_RUNNING); jtid->jlThread = jlThread; SET_COOKIE(jtid->jlThread); signal(STOP_SIGNAL, deathcallback); jtid->stop_allowed = 1; jtid->stop_pending = 0; jthread_setpriority(jtid, prio); rename_thread(jtid->native_thread, "Kaffe main thread"); return (jtid);}/* * set a function to be run when all non-daemon threads have exited */voidjthread_atexit(void (*f)(void)){ runOnExit = f;}/* * disallow cancellation */void jthread_disable_stop(void){ jthread_t currentJThread = GET_JTHREAD(); if (NULL != currentJThread) { atomic_and(¤tJThread->stop_allowed, 0); }}/* * reallow cancellation and stop if cancellation pending
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -