| /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| /* ***** BEGIN LICENSE BLOCK ***** |
| * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
| * |
| * The contents of this file are subject to the Mozilla Public License Version |
| * 1.1 (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * http://www.mozilla.org/MPL/ |
| * |
| * Software distributed under the License is distributed on an "AS IS" basis, |
| * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
| * for the specific language governing rights and limitations under the |
| * License. |
| * |
| * The Original Code is the Netscape Portable Runtime (NSPR). |
| * |
| * The Initial Developer of the Original Code is |
| * Netscape Communications Corporation. |
| * Portions created by the Initial Developer are Copyright (C) 1998-2000 |
| * the Initial Developer. All Rights Reserved. |
| * |
| * Contributor(s): |
| * |
| * Alternatively, the contents of this file may be used under the terms of |
| * either the GNU General Public License Version 2 or later (the "GPL"), or |
| * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
| * in which case the provisions of the GPL or the LGPL are applicable instead |
| * of those above. If you wish to allow use of your version of this file only |
| * under the terms of either the GPL or the LGPL, and not to allow others to |
| * use your version of this file under the terms of the MPL, indicate your |
| * decision by deleting the provisions above and replace them with the notice |
| * and other provisions required by the GPL or the LGPL. If you do not delete |
| * the provisions above, a recipient may use your version of this file under |
| * the terms of any one of the MPL, the GPL or the LGPL. |
| * |
| * ***** END LICENSE BLOCK ***** */ |
| |
| #include "primpl.h" |
| |
| #include <signal.h> |
| |
| #include <sys/types.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <sys/mman.h> |
| #include <sys/syssgi.h> |
| #include <sys/time.h> |
| #include <sys/immu.h> |
| #include <sys/utsname.h> |
| #include <sys/sysmp.h> |
| #include <sys/pda.h> |
| #include <sys/prctl.h> |
| #include <sys/wait.h> |
| #include <sys/resource.h> |
| #include <sys/procfs.h> |
| #include <task.h> |
| #include <dlfcn.h> |
| |
| static void _MD_IrixIntervalInit(void); |
| |
| #if defined(_PR_PTHREADS) |
| /* |
| * for compatibility with classic nspr |
| */ |
| void _PR_IRIX_CHILD_PROCESS() |
| { |
| } |
| #else /* defined(_PR_PTHREADS) */ |
| |
| static void irix_detach_sproc(void); |
| char *_nspr_sproc_private; /* ptr. to private region in every sproc */ |
| |
| extern PRUintn _pr_numCPU; |
| |
| typedef struct nspr_arena { |
| PRCList links; |
| usptr_t *usarena; |
| } nspr_arena; |
| |
| #define ARENA_PTR(qp) \ |
| ((nspr_arena *) ((char*) (qp) - offsetof(nspr_arena , links))) |
| |
| static usptr_t *alloc_new_arena(void); |
| |
| PRCList arena_list = PR_INIT_STATIC_CLIST(&arena_list); |
| ulock_t arena_list_lock; |
| nspr_arena first_arena; |
| int _nspr_irix_arena_cnt = 1; |
| |
| PRCList sproc_list = PR_INIT_STATIC_CLIST(&sproc_list); |
| ulock_t sproc_list_lock; |
| |
| typedef struct sproc_data { |
| void (*entry) (void *, size_t); |
| unsigned inh; |
| void *arg; |
| caddr_t sp; |
| size_t len; |
| int *pid; |
| int creator_pid; |
| } sproc_data; |
| |
| typedef struct sproc_params { |
| PRCList links; |
| sproc_data sd; |
| } sproc_params; |
| |
| #define SPROC_PARAMS_PTR(qp) \ |
| ((sproc_params *) ((char*) (qp) - offsetof(sproc_params , links))) |
| |
| long _nspr_irix_lock_cnt = 0; |
| long _nspr_irix_sem_cnt = 0; |
| long _nspr_irix_pollsem_cnt = 0; |
| |
| usptr_t *_pr_usArena; |
| ulock_t _pr_heapLock; |
| |
| usema_t *_pr_irix_exit_sem; |
| PRInt32 _pr_irix_exit_now = 0; |
| PRInt32 _pr_irix_process_exit_code = 0; /* exit code for PR_ProcessExit */ |
| PRInt32 _pr_irix_process_exit = 0; /* process exiting due to call to |
| PR_ProcessExit */ |
| |
| int _pr_irix_primoridal_cpu_fd[2] = { -1, -1 }; |
| static void (*libc_exit)(int) = NULL; |
| static void *libc_handle = NULL; |
| |
| #define _NSPR_DEF_INITUSERS 100 /* default value of CONF_INITUSERS */ |
| #define _NSPR_DEF_INITSIZE (4 * 1024 * 1024) /* 4 MB */ |
| |
| int _irix_initusers = _NSPR_DEF_INITUSERS; |
| int _irix_initsize = _NSPR_DEF_INITSIZE; |
| |
| PRIntn _pr_io_in_progress, _pr_clock_in_progress; |
| |
| PRInt32 _pr_md_irix_sprocs_created, _pr_md_irix_sprocs_failed; |
| PRInt32 _pr_md_irix_sprocs = 1; |
| PRCList _pr_md_irix_sproc_list = |
| PR_INIT_STATIC_CLIST(&_pr_md_irix_sproc_list); |
| |
| sigset_t ints_off; |
| extern sigset_t timer_set; |
| |
| #if !defined(PR_SETABORTSIG) |
| #define PR_SETABORTSIG 18 |
| #endif |
| /* |
| * terminate the entire application if any sproc exits abnormally |
| */ |
| PRBool _nspr_terminate_on_error = PR_TRUE; |
| |
| /* |
| * exported interface to set the shared arena parameters |
| */ |
| void _PR_Irix_Set_Arena_Params(PRInt32 initusers, PRInt32 initsize) |
| { |
| _irix_initusers = initusers; |
| _irix_initsize = initsize; |
| } |
| |
| static usptr_t *alloc_new_arena() |
| { |
| return(usinit("/dev/zero")); |
| } |
| |
| static PRStatus new_poll_sem(struct _MDThread *mdthr, int val) |
| { |
| PRIntn _is; |
| PRStatus rv = PR_SUCCESS; |
| usema_t *sem = NULL; |
| PRCList *qp; |
| nspr_arena *arena; |
| usptr_t *irix_arena; |
| PRThread *me = _MD_GET_ATTACHED_THREAD(); |
| |
| if (me && !_PR_IS_NATIVE_THREAD(me)) |
| _PR_INTSOFF(_is); |
| _PR_LOCK(arena_list_lock); |
| for (qp = arena_list.next; qp != &arena_list; qp = qp->next) { |
| arena = ARENA_PTR(qp); |
| sem = usnewpollsema(arena->usarena, val); |
| if (sem != NULL) { |
| mdthr->cvar_pollsem = sem; |
| mdthr->pollsem_arena = arena->usarena; |
| break; |
| } |
| } |
| if (sem == NULL) { |
| /* |
| * If no space left in the arena allocate a new one. |
| */ |
| if (errno == ENOMEM) { |
| arena = PR_NEWZAP(nspr_arena); |
| if (arena != NULL) { |
| irix_arena = alloc_new_arena(); |
| if (irix_arena) { |
| PR_APPEND_LINK(&arena->links, &arena_list); |
| _nspr_irix_arena_cnt++; |
| arena->usarena = irix_arena; |
| sem = usnewpollsema(arena->usarena, val); |
| if (sem != NULL) { |
| mdthr->cvar_pollsem = sem; |
| mdthr->pollsem_arena = arena->usarena; |
| } else |
| rv = PR_FAILURE; |
| } else { |
| PR_DELETE(arena); |
| rv = PR_FAILURE; |
| } |
| |
| } else |
| rv = PR_FAILURE; |
| } else |
| rv = PR_FAILURE; |
| } |
| _PR_UNLOCK(arena_list_lock); |
| if (me && !_PR_IS_NATIVE_THREAD(me)) |
| _PR_FAST_INTSON(_is); |
| if (rv == PR_SUCCESS) |
| _MD_ATOMIC_INCREMENT(&_nspr_irix_pollsem_cnt); |
| return rv; |
| } |
| |
| static void free_poll_sem(struct _MDThread *mdthr) |
| { |
| PRIntn _is; |
| PRThread *me = _MD_GET_ATTACHED_THREAD(); |
| |
| if (me && !_PR_IS_NATIVE_THREAD(me)) |
| _PR_INTSOFF(_is); |
| usfreepollsema(mdthr->cvar_pollsem, mdthr->pollsem_arena); |
| if (me && !_PR_IS_NATIVE_THREAD(me)) |
| _PR_FAST_INTSON(_is); |
| _MD_ATOMIC_DECREMENT(&_nspr_irix_pollsem_cnt); |
| } |
| |
| static PRStatus new_lock(struct _MDLock *lockp) |
| { |
| PRIntn _is; |
| PRStatus rv = PR_SUCCESS; |
| ulock_t lock = NULL; |
| PRCList *qp; |
| nspr_arena *arena; |
| usptr_t *irix_arena; |
| PRThread *me = _MD_GET_ATTACHED_THREAD(); |
| |
| if (me && !_PR_IS_NATIVE_THREAD(me)) |
| _PR_INTSOFF(_is); |
| _PR_LOCK(arena_list_lock); |
| for (qp = arena_list.next; qp != &arena_list; qp = qp->next) { |
| arena = ARENA_PTR(qp); |
| lock = usnewlock(arena->usarena); |
| if (lock != NULL) { |
| lockp->lock = lock; |
| lockp->arena = arena->usarena; |
| break; |
| } |
| } |
| if (lock == NULL) { |
| /* |
| * If no space left in the arena allocate a new one. |
| */ |
| if (errno == ENOMEM) { |
| arena = PR_NEWZAP(nspr_arena); |
| if (arena != NULL) { |
| irix_arena = alloc_new_arena(); |
| if (irix_arena) { |
| PR_APPEND_LINK(&arena->links, &arena_list); |
| _nspr_irix_arena_cnt++; |
| arena->usarena = irix_arena; |
| lock = usnewlock(irix_arena); |
| if (lock != NULL) { |
| lockp->lock = lock; |
| lockp->arena = arena->usarena; |
| } else |
| rv = PR_FAILURE; |
| } else { |
| PR_DELETE(arena); |
| rv = PR_FAILURE; |
| } |
| |
| } else |
| rv = PR_FAILURE; |
| } else |
| rv = PR_FAILURE; |
| } |
| _PR_UNLOCK(arena_list_lock); |
| if (me && !_PR_IS_NATIVE_THREAD(me)) |
| _PR_FAST_INTSON(_is); |
| if (rv == PR_SUCCESS) |
| _MD_ATOMIC_INCREMENT(&_nspr_irix_lock_cnt); |
| return rv; |
| } |
| |
| static void free_lock(struct _MDLock *lockp) |
| { |
| PRIntn _is; |
| PRThread *me = _MD_GET_ATTACHED_THREAD(); |
| |
| if (me && !_PR_IS_NATIVE_THREAD(me)) |
| _PR_INTSOFF(_is); |
| usfreelock(lockp->lock, lockp->arena); |
| if (me && !_PR_IS_NATIVE_THREAD(me)) |
| _PR_FAST_INTSON(_is); |
| _MD_ATOMIC_DECREMENT(&_nspr_irix_lock_cnt); |
| } |
| |
| void _MD_FREE_LOCK(struct _MDLock *lockp) |
| { |
| PRIntn _is; |
| PRThread *me = _MD_GET_ATTACHED_THREAD(); |
| |
| if (me && !_PR_IS_NATIVE_THREAD(me)) |
| _PR_INTSOFF(_is); |
| free_lock(lockp); |
| if (me && !_PR_IS_NATIVE_THREAD(me)) |
| _PR_FAST_INTSON(_is); |
| } |
| |
| /* |
| * _MD_get_attached_thread |
| * Return the thread pointer of the current thread if it is attached. |
| * |
| * This function is needed for Irix because the thread-local-storage is |
| * implemented by mmapin'g a page with the MAP_LOCAL flag. This causes the |
| * sproc-private page to inherit contents of the page of the caller of sproc(). |
| */ |
| PRThread *_MD_get_attached_thread(void) |
| { |
| |
| if (_MD_GET_SPROC_PID() == get_pid()) |
| return _MD_THIS_THREAD(); |
| else |
| return 0; |
| } |
| |
| /* |
| * _MD_get_current_thread |
| * Return the thread pointer of the current thread (attaching it if |
| * necessary) |
| */ |
| PRThread *_MD_get_current_thread(void) |
| { |
| PRThread *me; |
| |
| me = _MD_GET_ATTACHED_THREAD(); |
| if (NULL == me) { |
| me = _PRI_AttachThread( |
| PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0); |
| } |
| PR_ASSERT(me != NULL); |
| return(me); |
| } |
| |
| /* |
| * irix_detach_sproc |
| * auto-detach a sproc when it exits |
| */ |
| void irix_detach_sproc(void) |
| { |
| PRThread *me; |
| |
| me = _MD_GET_ATTACHED_THREAD(); |
| if ((me != NULL) && (me->flags & _PR_ATTACHED)) { |
| _PRI_DetachThread(); |
| } |
| } |
| |
| |
| PRStatus _MD_NEW_LOCK(struct _MDLock *lockp) |
| { |
| PRStatus rv; |
| PRIntn is; |
| PRThread *me = _MD_GET_ATTACHED_THREAD(); |
| |
| if (me && !_PR_IS_NATIVE_THREAD(me)) |
| _PR_INTSOFF(is); |
| rv = new_lock(lockp); |
| if (me && !_PR_IS_NATIVE_THREAD(me)) |
| _PR_FAST_INTSON(is); |
| return rv; |
| } |
| |
| static void |
| sigchld_handler(int sig) |
| { |
| pid_t pid; |
| int status; |
| |
| /* |
| * If an sproc exited abnormally send a SIGKILL signal to all the |
| * sprocs in the process to terminate the application |
| */ |
| while ((pid = waitpid(0, &status, WNOHANG)) > 0) { |
| if (WIFSIGNALED(status) && ((WTERMSIG(status) == SIGSEGV) || |
| (WTERMSIG(status) == SIGBUS) || |
| (WTERMSIG(status) == SIGABRT) || |
| (WTERMSIG(status) == SIGILL))) { |
| |
| prctl(PR_SETEXITSIG, SIGKILL); |
| _exit(status); |
| } |
| } |
| } |
| |
| static void save_context_and_block(int sig) |
| { |
| PRThread *me = _PR_MD_CURRENT_THREAD(); |
| _PRCPU *cpu = _PR_MD_CURRENT_CPU(); |
| |
| /* |
| * save context |
| */ |
| (void) setjmp(me->md.jb); |
| /* |
| * unblock the suspending thread |
| */ |
| if (me->cpu) { |
| /* |
| * I am a cpu thread, not a user-created GLOBAL thread |
| */ |
| unblockproc(cpu->md.suspending_id); |
| } else { |
| unblockproc(me->md.suspending_id); |
| } |
| /* |
| * now, block current thread |
| */ |
| blockproc(getpid()); |
| } |
| |
| /* |
| ** The irix kernel has a bug in it which causes async connect's which are |
| ** interrupted by a signal to fail terribly (EADDRINUSE is returned). |
| ** We work around the bug by blocking signals during the async connect |
| ** attempt. |
| */ |
| PRInt32 _MD_irix_connect( |
| PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen, PRIntervalTime timeout) |
| { |
| PRInt32 rv; |
| sigset_t oldset; |
| |
| sigprocmask(SIG_BLOCK, &ints_off, &oldset); |
| rv = connect(osfd, addr, addrlen); |
| sigprocmask(SIG_SETMASK, &oldset, 0); |
| |
| return(rv); |
| } |
| |
| #include "prprf.h" |
| |
| /********************************************************************/ |
| /********************************************************************/ |
| /*************** Various thread like things for IRIX ****************/ |
| /********************************************************************/ |
| /********************************************************************/ |
| |
| void *_MD_GetSP(PRThread *t) |
| { |
| PRThread *me = _PR_MD_CURRENT_THREAD(); |
| void *sp; |
| |
| if (me == t) |
| (void) setjmp(t->md.jb); |
| |
| sp = (void *)(t->md.jb[JB_SP]); |
| PR_ASSERT((sp >= (void *) t->stack->stackBottom) && |
| (sp <= (void *) (t->stack->stackBottom + t->stack->stackSize))); |
| return(sp); |
| } |
| |
| void _MD_InitLocks() |
| { |
| char buf[200]; |
| char *init_users, *init_size; |
| |
| PR_snprintf(buf, sizeof(buf), "/dev/zero"); |
| |
| if (init_users = getenv("_NSPR_IRIX_INITUSERS")) |
| _irix_initusers = atoi(init_users); |
| |
| if (init_size = getenv("_NSPR_IRIX_INITSIZE")) |
| _irix_initsize = atoi(init_size); |
| |
| usconfig(CONF_INITUSERS, _irix_initusers); |
| usconfig(CONF_INITSIZE, _irix_initsize); |
| usconfig(CONF_AUTOGROW, 1); |
| usconfig(CONF_AUTORESV, 1); |
| if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0) { |
| perror("PR_Init: unable to config mutex arena"); |
| exit(-1); |
| } |
| |
| _pr_usArena = usinit(buf); |
| if (!_pr_usArena) { |
| fprintf(stderr, |
| "PR_Init: Error - unable to create lock/monitor arena\n"); |
| exit(-1); |
| } |
| _pr_heapLock = usnewlock(_pr_usArena); |
| _nspr_irix_lock_cnt++; |
| |
| arena_list_lock = usnewlock(_pr_usArena); |
| _nspr_irix_lock_cnt++; |
| |
| sproc_list_lock = usnewlock(_pr_usArena); |
| _nspr_irix_lock_cnt++; |
| |
| _pr_irix_exit_sem = usnewsema(_pr_usArena, 0); |
| _nspr_irix_sem_cnt = 1; |
| |
| first_arena.usarena = _pr_usArena; |
| PR_INIT_CLIST(&first_arena.links); |
| PR_APPEND_LINK(&first_arena.links, &arena_list); |
| } |
| |
| /* _PR_IRIX_CHILD_PROCESS is a private API for Server group */ |
| void _PR_IRIX_CHILD_PROCESS() |
| { |
| extern PRUint32 _pr_global_threads; |
| |
| PR_ASSERT(_PR_MD_CURRENT_CPU() == _pr_primordialCPU); |
| PR_ASSERT(_pr_numCPU == 1); |
| PR_ASSERT(_pr_global_threads == 0); |
| /* |
| * save the new pid |
| */ |
| _pr_primordialCPU->md.id = getpid(); |
| _MD_SET_SPROC_PID(getpid()); |
| } |
| |
| static PRStatus pr_cvar_wait_sem(PRThread *thread, PRIntervalTime timeout) |
| { |
| int rv; |
| |
| #ifdef _PR_USE_POLL |
| struct pollfd pfd; |
| int msecs; |
| |
| if (timeout == PR_INTERVAL_NO_TIMEOUT) |
| msecs = -1; |
| else |
| msecs = PR_IntervalToMilliseconds(timeout); |
| #else |
| struct timeval tv, *tvp; |
| fd_set rd; |
| |
| if(timeout == PR_INTERVAL_NO_TIMEOUT) |
| tvp = NULL; |
| else { |
| tv.tv_sec = PR_IntervalToSeconds(timeout); |
| tv.tv_usec = PR_IntervalToMicroseconds( |
| timeout - PR_SecondsToInterval(tv.tv_sec)); |
| tvp = &tv; |
| } |
| FD_ZERO(&rd); |
| FD_SET(thread->md.cvar_pollsemfd, &rd); |
| #endif |
| |
| /* |
| * call uspsema only if a previous select call on this semaphore |
| * did not timeout |
| */ |
| if (!thread->md.cvar_pollsem_select) { |
| rv = _PR_WAIT_SEM(thread->md.cvar_pollsem); |
| PR_ASSERT(rv >= 0); |
| } else |
| rv = 0; |
| again: |
| if(!rv) { |
| #ifdef _PR_USE_POLL |
| pfd.events = POLLIN; |
| pfd.fd = thread->md.cvar_pollsemfd; |
| rv = _MD_POLL(&pfd, 1, msecs); |
| #else |
| rv = _MD_SELECT(thread->md.cvar_pollsemfd + 1, &rd, NULL,NULL,tvp); |
| #endif |
| if ((rv == -1) && (errno == EINTR)) { |
| rv = 0; |
| goto again; |
| } |
| PR_ASSERT(rv >= 0); |
| } |
| |
| if (rv > 0) { |
| /* |
| * acquired the semaphore, call uspsema next time |
| */ |
| thread->md.cvar_pollsem_select = 0; |
| return PR_SUCCESS; |
| } else { |
| /* |
| * select timed out; must call select, not uspsema, when trying |
| * to acquire the semaphore the next time |
| */ |
| thread->md.cvar_pollsem_select = 1; |
| return PR_FAILURE; |
| } |
| } |
| |
| PRStatus _MD_wait(PRThread *thread, PRIntervalTime ticks) |
| { |
| if ( thread->flags & _PR_GLOBAL_SCOPE ) { |
| _MD_CHECK_FOR_EXIT(); |
| if (pr_cvar_wait_sem(thread, ticks) == PR_FAILURE) { |
| _MD_CHECK_FOR_EXIT(); |
| /* |
| * wait timed out |
| */ |
| _PR_THREAD_LOCK(thread); |
| if (thread->wait.cvar) { |
| /* |
| * The thread will remove itself from the waitQ |
| * of the cvar in _PR_WaitCondVar |
| */ |
| thread->wait.cvar = NULL; |
| thread->state = _PR_RUNNING; |
| _PR_THREAD_UNLOCK(thread); |
| } else { |
| _PR_THREAD_UNLOCK(thread); |
| /* |
| * This thread was woken up by a notifying thread |
| * at the same time as a timeout; so, consume the |
| * extra post operation on the semaphore |
| */ |
| _MD_CHECK_FOR_EXIT(); |
| pr_cvar_wait_sem(thread, PR_INTERVAL_NO_TIMEOUT); |
| } |
| _MD_CHECK_FOR_EXIT(); |
| } |
| } else { |
| _PR_MD_SWITCH_CONTEXT(thread); |
| } |
| return PR_SUCCESS; |
| } |
| |
| PRStatus _MD_WakeupWaiter(PRThread *thread) |
| { |
| PRThread *me = _PR_MD_CURRENT_THREAD(); |
| PRIntn is; |
| |
| PR_ASSERT(_pr_md_idle_cpus >= 0); |
| if (thread == NULL) { |
| if (_pr_md_idle_cpus) |
| _MD_Wakeup_CPUs(); |
| } else if (!_PR_IS_NATIVE_THREAD(thread)) { |
| if (_pr_md_idle_cpus) |
| _MD_Wakeup_CPUs(); |
| } else { |
| PR_ASSERT(_PR_IS_NATIVE_THREAD(thread)); |
| if (!_PR_IS_NATIVE_THREAD(me)) |
| _PR_INTSOFF(is); |
| _MD_CVAR_POST_SEM(thread); |
| if (!_PR_IS_NATIVE_THREAD(me)) |
| _PR_FAST_INTSON(is); |
| } |
| return PR_SUCCESS; |
| } |
| |
| void create_sproc (void (*entry) (void *, size_t), unsigned inh, |
| void *arg, caddr_t sp, size_t len, int *pid) |
| { |
| sproc_params sparams; |
| char data; |
| int rv; |
| PRThread *me = _PR_MD_CURRENT_THREAD(); |
| |
| if (!_PR_IS_NATIVE_THREAD(me) && (_PR_MD_CURRENT_CPU()->id == 0)) { |
| *pid = sprocsp(entry, /* startup func */ |
| inh, /* attribute flags */ |
| arg, /* thread param */ |
| sp, /* stack address */ |
| len); /* stack size */ |
| } else { |
| sparams.sd.entry = entry; |
| sparams.sd.inh = inh; |
| sparams.sd.arg = arg; |
| sparams.sd.sp = sp; |
| sparams.sd.len = len; |
| sparams.sd.pid = pid; |
| sparams.sd.creator_pid = getpid(); |
| _PR_LOCK(sproc_list_lock); |
| PR_APPEND_LINK(&sparams.links, &sproc_list); |
| rv = write(_pr_irix_primoridal_cpu_fd[1], &data, 1); |
| PR_ASSERT(rv == 1); |
| _PR_UNLOCK(sproc_list_lock); |
| blockproc(getpid()); |
| } |
| } |
| |
| /* |
| * _PR_MD_WAKEUP_PRIMORDIAL_CPU |
| * |
| * wakeup cpu 0 |
| */ |
| |
| void _PR_MD_WAKEUP_PRIMORDIAL_CPU() |
| { |
| char data = '0'; |
| int rv; |
| |
| rv = write(_pr_irix_primoridal_cpu_fd[1], &data, 1); |
| PR_ASSERT(rv == 1); |
| } |
| |
| /* |
| * _PR_MD_primordial_cpu |
| * |
| * process events that need to executed by the primordial cpu on each |
| * iteration through the idle loop |
| */ |
| |
| void _PR_MD_primordial_cpu() |
| { |
| PRCList *qp; |
| sproc_params *sp; |
| int pid; |
| |
| _PR_LOCK(sproc_list_lock); |
| while ((qp = sproc_list.next) != &sproc_list) { |
| sp = SPROC_PARAMS_PTR(qp); |
| PR_REMOVE_LINK(&sp->links); |
| pid = sp->sd.creator_pid; |
| (*(sp->sd.pid)) = sprocsp(sp->sd.entry, /* startup func */ |
| sp->sd.inh, /* attribute flags */ |
| sp->sd.arg, /* thread param */ |
| sp->sd.sp, /* stack address */ |
| sp->sd.len); /* stack size */ |
| unblockproc(pid); |
| } |
| _PR_UNLOCK(sproc_list_lock); |
| } |
| |
| PRStatus _MD_CreateThread(PRThread *thread, |
| void (*start)(void *), |
| PRThreadPriority priority, |
| PRThreadScope scope, |
| PRThreadState state, |
| PRUint32 stackSize) |
| { |
| typedef void (*SprocEntry) (void *, size_t); |
| SprocEntry spentry = (SprocEntry)start; |
| PRIntn is; |
| PRThread *me = _PR_MD_CURRENT_THREAD(); |
| PRInt32 pid; |
| PRStatus rv; |
| |
| if (!_PR_IS_NATIVE_THREAD(me)) |
| _PR_INTSOFF(is); |
| thread->md.cvar_pollsem_select = 0; |
| thread->flags |= _PR_GLOBAL_SCOPE; |
| |
| thread->md.cvar_pollsemfd = -1; |
| if (new_poll_sem(&thread->md,0) == PR_FAILURE) { |
| if (!_PR_IS_NATIVE_THREAD(me)) |
| _PR_FAST_INTSON(is); |
| return PR_FAILURE; |
| } |
| thread->md.cvar_pollsemfd = |
| _PR_OPEN_POLL_SEM(thread->md.cvar_pollsem); |
| if ((thread->md.cvar_pollsemfd < 0)) { |
| free_poll_sem(&thread->md); |
| if (!_PR_IS_NATIVE_THREAD(me)) |
| _PR_FAST_INTSON(is); |
| return PR_FAILURE; |
| } |
| |
| create_sproc(spentry, /* startup func */ |
| PR_SALL, /* attribute flags */ |
| (void *)thread, /* thread param */ |
| NULL, /* stack address */ |
| stackSize, &pid); /* stack size */ |
| if (pid > 0) { |
| _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs_created); |
| _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs); |
| rv = PR_SUCCESS; |
| if (!_PR_IS_NATIVE_THREAD(me)) |
| _PR_FAST_INTSON(is); |
| return rv; |
| } else { |
| close(thread->md.cvar_pollsemfd); |
| thread->md.cvar_pollsemfd = -1; |
| free_poll_sem(&thread->md); |
| thread->md.cvar_pollsem = NULL; |
| _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs_failed); |
| if (!_PR_IS_NATIVE_THREAD(me)) |
| _PR_FAST_INTSON(is); |
| return PR_FAILURE; |
| } |
| } |
| |
| void _MD_CleanThread(PRThread *thread) |
| { |
| if (thread->flags & _PR_GLOBAL_SCOPE) { |
| close(thread->md.cvar_pollsemfd); |
| thread->md.cvar_pollsemfd = -1; |
| free_poll_sem(&thread->md); |
| thread->md.cvar_pollsem = NULL; |
| } |
| } |
| |
| void _MD_SetPriority(_MDThread *thread, PRThreadPriority newPri) |
| { |
| return; |
| } |
| |
| extern void _MD_unix_terminate_waitpid_daemon(void); |
| |
| void |
| _MD_CleanupBeforeExit(void) |
| { |
| extern PRInt32 _pr_cpus_exit; |
| |
| _MD_unix_terminate_waitpid_daemon(); |
| |
| _pr_irix_exit_now = 1; |
| if (_pr_numCPU > 1) { |
| /* |
| * Set a global flag, and wakeup all cpus which will notice the flag |
| * and exit. |
| */ |
| _pr_cpus_exit = getpid(); |
| _MD_Wakeup_CPUs(); |
| while(_pr_numCPU > 1) { |
| _PR_WAIT_SEM(_pr_irix_exit_sem); |
| _pr_numCPU--; |
| } |
| } |
| /* |
| * cause global threads on the recycle list to exit |
| */ |
| _PR_DEADQ_LOCK; |
| if (_PR_NUM_DEADNATIVE != 0) { |
| PRThread *thread; |
| PRCList *ptr; |
| |
| ptr = _PR_DEADNATIVEQ.next; |
| while( ptr != &_PR_DEADNATIVEQ ) { |
| thread = _PR_THREAD_PTR(ptr); |
| _MD_CVAR_POST_SEM(thread); |
| ptr = ptr->next; |
| } |
| } |
| _PR_DEADQ_UNLOCK; |
| while(_PR_NUM_DEADNATIVE > 1) { |
| _PR_WAIT_SEM(_pr_irix_exit_sem); |
| _PR_DEC_DEADNATIVE; |
| } |
| } |
| |
| #ifdef _PR_HAVE_SGI_PRDA_PROCMASK |
| extern void __sgi_prda_procmask(int); |
| #endif |
| |
| PRStatus |
| _MD_InitAttachedThread(PRThread *thread, PRBool wakeup_parent) |
| { |
| PRStatus rv = PR_SUCCESS; |
| |
| if (thread->flags & _PR_GLOBAL_SCOPE) { |
| if (new_poll_sem(&thread->md,0) == PR_FAILURE) { |
| return PR_FAILURE; |
| } |
| thread->md.cvar_pollsemfd = |
| _PR_OPEN_POLL_SEM(thread->md.cvar_pollsem); |
| if ((thread->md.cvar_pollsemfd < 0)) { |
| free_poll_sem(&thread->md); |
| return PR_FAILURE; |
| } |
| if (_MD_InitThread(thread, PR_FALSE) == PR_FAILURE) { |
| close(thread->md.cvar_pollsemfd); |
| thread->md.cvar_pollsemfd = -1; |
| free_poll_sem(&thread->md); |
| thread->md.cvar_pollsem = NULL; |
| return PR_FAILURE; |
| } |
| } |
| return rv; |
| } |
| |
| PRStatus |
| _MD_InitThread(PRThread *thread, PRBool wakeup_parent) |
| { |
| struct sigaction sigact; |
| PRStatus rv = PR_SUCCESS; |
| |
| if (thread->flags & _PR_GLOBAL_SCOPE) { |
| thread->md.id = getpid(); |
| setblockproccnt(thread->md.id, 0); |
| _MD_SET_SPROC_PID(getpid()); |
| #ifdef _PR_HAVE_SGI_PRDA_PROCMASK |
| /* |
| * enable user-level processing of sigprocmask(); this is an |
| * undocumented feature available in Irix 6.2, 6.3, 6.4 and 6.5 |
| */ |
| __sgi_prda_procmask(USER_LEVEL); |
| #endif |
| /* |
| * set up SIGUSR1 handler; this is used to save state |
| */ |
| sigact.sa_handler = save_context_and_block; |
| sigact.sa_flags = SA_RESTART; |
| /* |
| * Must mask clock interrupts |
| */ |
| sigact.sa_mask = timer_set; |
| sigaction(SIGUSR1, &sigact, 0); |
| |
| |
| /* |
| * PR_SETABORTSIG is a new command implemented in a patch to |
| * Irix 6.2, 6.3 and 6.4. This causes a signal to be sent to all |
| * sprocs in the process when one of them terminates abnormally |
| * |
| */ |
| if (prctl(PR_SETABORTSIG, SIGKILL) < 0) { |
| /* |
| * if (errno == EINVAL) |
| * |
| * PR_SETABORTSIG not supported under this OS. |
| * You may want to get a recent kernel rollup patch that |
| * supports this feature. |
| */ |
| } |
| /* |
| * SIGCLD handler for detecting abormally-terminating |
| * sprocs and for reaping sprocs |
| */ |
| sigact.sa_handler = sigchld_handler; |
| sigact.sa_flags = SA_RESTART; |
| sigact.sa_mask = ints_off; |
| sigaction(SIGCLD, &sigact, NULL); |
| } |
| return rv; |
| } |
| |
| /* |
| * PR_Cleanup should be executed on the primordial sproc; migrate the thread |
| * to the primordial cpu |
| */ |
| |
| void _PR_MD_PRE_CLEANUP(PRThread *me) |
| { |
| PRIntn is; |
| _PRCPU *cpu = _pr_primordialCPU; |
| |
| PR_ASSERT(cpu); |
| |
| me->flags |= _PR_BOUND_THREAD; |
| |
| if (me->cpu->id != 0) { |
| _PR_INTSOFF(is); |
| _PR_RUNQ_LOCK(cpu); |
| me->cpu = cpu; |
| me->state = _PR_RUNNABLE; |
| _PR_ADD_RUNQ(me, cpu, me->priority); |
| _PR_RUNQ_UNLOCK(cpu); |
| _MD_Wakeup_CPUs(); |
| |
| _PR_MD_SWITCH_CONTEXT(me); |
| |
| _PR_FAST_INTSON(is); |
| PR_ASSERT(me->cpu->id == 0); |
| } |
| } |
| |
| /* |
| * process exiting |
| */ |
| PR_EXTERN(void ) _MD_exit(PRIntn status) |
| { |
| PRThread *me = _PR_MD_CURRENT_THREAD(); |
| |
| /* |
| * the exit code of the process is the exit code of the primordial |
| * sproc |
| */ |
| if (!_PR_IS_NATIVE_THREAD(me) && (_PR_MD_CURRENT_CPU()->id == 0)) { |
| /* |
| * primordial sproc case: call _exit directly |
| * Cause SIGKILL to be sent to other sprocs |
| */ |
| prctl(PR_SETEXITSIG, SIGKILL); |
| _exit(status); |
| } else { |
| int rv; |
| char data; |
| sigset_t set; |
| |
| /* |
| * non-primordial sproc case: cause the primordial sproc, cpu 0, |
| * to wakeup and call _exit |
| */ |
| _pr_irix_process_exit = 1; |
| _pr_irix_process_exit_code = status; |
| rv = write(_pr_irix_primoridal_cpu_fd[1], &data, 1); |
| PR_ASSERT(rv == 1); |
| /* |
| * block all signals and wait for SIGKILL to terminate this sproc |
| */ |
| sigfillset(&set); |
| sigsuspend(&set); |
| /* |
| * this code doesn't (shouldn't) execute |
| */ |
| prctl(PR_SETEXITSIG, SIGKILL); |
| _exit(status); |
| } |
| } |
| |
| /* |
| * Override the exit() function in libc to cause the process to exit |
| * when the primodial/main nspr thread calls exit. Calls to exit by any |
| * other thread simply result in a call to the exit function in libc. |
| * The exit code of the process is the exit code of the primordial |
| * sproc. |
| */ |
| |
| void exit(int status) |
| { |
| PRThread *me, *thr; |
| PRCList *qp; |
| |
| if (!_pr_initialized) { |
| if (!libc_exit) { |
| |
| if (!libc_handle) |
| libc_handle = dlopen("libc.so",RTLD_NOW); |
| if (libc_handle) |
| libc_exit = (void (*)(int)) dlsym(libc_handle, "exit"); |
| } |
| if (libc_exit) |
| (*libc_exit)(status); |
| else |
| _exit(status); |
| } |
| |
| me = _PR_MD_CURRENT_THREAD(); |
| |
| if (me == NULL) /* detached thread */ |
| (*libc_exit)(status); |
| |
| PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || |
| (_PR_MD_CURRENT_CPU())->id == me->cpu->id); |
| |
| if (me->flags & _PR_PRIMORDIAL) { |
| |
| me->flags |= _PR_BOUND_THREAD; |
| |
| PR_ASSERT((_PR_MD_CURRENT_CPU())->id == me->cpu->id); |
| if (me->cpu->id != 0) { |
| _PRCPU *cpu = _pr_primordialCPU; |
| PRIntn is; |
| |
| _PR_INTSOFF(is); |
| _PR_RUNQ_LOCK(cpu); |
| me->cpu = cpu; |
| me->state = _PR_RUNNABLE; |
| _PR_ADD_RUNQ(me, cpu, me->priority); |
| _PR_RUNQ_UNLOCK(cpu); |
| _MD_Wakeup_CPUs(); |
| |
| _PR_MD_SWITCH_CONTEXT(me); |
| |
| _PR_FAST_INTSON(is); |
| } |
| |
| PR_ASSERT((_PR_MD_CURRENT_CPU())->id == 0); |
| |
| if (prctl(PR_GETNSHARE) > 1) { |
| #define SPROC_EXIT_WAIT_TIME 5 |
| int sleep_cnt = SPROC_EXIT_WAIT_TIME; |
| |
| /* |
| * sprocs still running; caue cpus and recycled global threads |
| * to exit |
| */ |
| _pr_irix_exit_now = 1; |
| if (_pr_numCPU > 1) { |
| _MD_Wakeup_CPUs(); |
| } |
| _PR_DEADQ_LOCK; |
| if (_PR_NUM_DEADNATIVE != 0) { |
| PRThread *thread; |
| PRCList *ptr; |
| |
| ptr = _PR_DEADNATIVEQ.next; |
| while( ptr != &_PR_DEADNATIVEQ ) { |
| thread = _PR_THREAD_PTR(ptr); |
| _MD_CVAR_POST_SEM(thread); |
| ptr = ptr->next; |
| } |
| } |
| |
| while (sleep_cnt-- > 0) { |
| if (waitpid(0, NULL, WNOHANG) >= 0) |
| sleep(1); |
| else |
| break; |
| } |
| prctl(PR_SETEXITSIG, SIGKILL); |
| } |
| (*libc_exit)(status); |
| } else { |
| /* |
| * non-primordial thread; simply call exit in libc. |
| */ |
| (*libc_exit)(status); |
| } |
| } |
| |
| |
| void |
| _MD_InitRunningCPU(_PRCPU *cpu) |
| { |
| extern int _pr_md_pipefd[2]; |
| |
| _MD_unix_init_running_cpu(cpu); |
| cpu->md.id = getpid(); |
| _MD_SET_SPROC_PID(getpid()); |
| if (_pr_md_pipefd[0] >= 0) { |
| _PR_IOQ_MAX_OSFD(cpu) = _pr_md_pipefd[0]; |
| #ifndef _PR_USE_POLL |
| FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(cpu)); |
| #endif |
| } |
| } |
| |
| void |
| _MD_ExitThread(PRThread *thread) |
| { |
| if (thread->flags & _PR_GLOBAL_SCOPE) { |
| _MD_ATOMIC_DECREMENT(&_pr_md_irix_sprocs); |
| _MD_CLEAN_THREAD(thread); |
| _MD_SET_CURRENT_THREAD(NULL); |
| } |
| } |
| |
| void |
| _MD_SuspendCPU(_PRCPU *cpu) |
| { |
| PRInt32 rv; |
| |
| cpu->md.suspending_id = getpid(); |
| rv = kill(cpu->md.id, SIGUSR1); |
| PR_ASSERT(rv == 0); |
| /* |
| * now, block the current thread/cpu until woken up by the suspended |
| * thread from it's SIGUSR1 signal handler |
| */ |
| blockproc(getpid()); |
| |
| } |
| |
| void |
| _MD_ResumeCPU(_PRCPU *cpu) |
| { |
| unblockproc(cpu->md.id); |
| } |
| |
| #if 0 |
| /* |
| * save the register context of a suspended sproc |
| */ |
| void get_context(PRThread *thr) |
| { |
| int len, fd; |
| char pidstr[24]; |
| char path[24]; |
| |
| /* |
| * open the file corresponding to this process in procfs |
| */ |
| sprintf(path,"/proc/%s","00000"); |
| len = strlen(path); |
| sprintf(pidstr,"%d",thr->md.id); |
| len -= strlen(pidstr); |
| sprintf(path + len,"%s",pidstr); |
| fd = open(path,O_RDONLY); |
| if (fd >= 0) { |
| (void) ioctl(fd, PIOCGREG, thr->md.gregs); |
| close(fd); |
| } |
| return; |
| } |
| #endif /* 0 */ |
| |
| void |
| _MD_SuspendThread(PRThread *thread) |
| { |
| PRInt32 rv; |
| |
| PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) && |
| _PR_IS_GCABLE_THREAD(thread)); |
| |
| thread->md.suspending_id = getpid(); |
| rv = kill(thread->md.id, SIGUSR1); |
| PR_ASSERT(rv == 0); |
| /* |
| * now, block the current thread/cpu until woken up by the suspended |
| * thread from it's SIGUSR1 signal handler |
| */ |
| blockproc(getpid()); |
| } |
| |
| void |
| _MD_ResumeThread(PRThread *thread) |
| { |
| PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) && |
| _PR_IS_GCABLE_THREAD(thread)); |
| (void)unblockproc(thread->md.id); |
| } |
| |
| /* |
| * return the set of processors available for scheduling procs in the |
| * "mask" argument |
| */ |
| PRInt32 _MD_GetThreadAffinityMask(PRThread *unused, PRUint32 *mask) |
| { |
| PRInt32 nprocs, rv; |
| struct pda_stat *pstat; |
| #define MAX_PROCESSORS 32 |
| |
| nprocs = sysmp(MP_NPROCS); |
| if (nprocs < 0) |
| return(-1); |
| pstat = (struct pda_stat*)PR_MALLOC(sizeof(struct pda_stat) * nprocs); |
| if (pstat == NULL) |
| return(-1); |
| rv = sysmp(MP_STAT, pstat); |
| if (rv < 0) { |
| PR_DELETE(pstat); |
| return(-1); |
| } |
| /* |
| * look at the first 32 cpus |
| */ |
| nprocs = (nprocs > MAX_PROCESSORS) ? MAX_PROCESSORS : nprocs; |
| *mask = 0; |
| while (nprocs) { |
| if ((pstat->p_flags & PDAF_ENABLED) && |
| !(pstat->p_flags & PDAF_ISOLATED)) { |
| *mask |= (1 << pstat->p_cpuid); |
| } |
| nprocs--; |
| pstat++; |
| } |
| return 0; |
| } |
| |
| static char *_thr_state[] = { |
| "UNBORN", |
| "RUNNABLE", |
| "RUNNING", |
| "LOCK_WAIT", |
| "COND_WAIT", |
| "JOIN_WAIT", |
| "IO_WAIT", |
| "SUSPENDED", |
| "DEAD" |
| }; |
| |
| void _PR_List_Threads() |
| { |
| PRThread *thr; |
| void *handle; |
| struct _PRCPU *cpu; |
| PRCList *qp; |
| int len, fd; |
| char pidstr[24]; |
| char path[24]; |
| prpsinfo_t pinfo; |
| |
| |
| printf("\n%s %-s\n"," ","LOCAL Threads"); |
| printf("%s %-s\n"," ","----- -------"); |
| printf("%s %-14s %-10s %-12s %-3s %-10s %-10s %-12s\n\n"," ", |
| "Thread", "State", "Wait-Handle", |
| "Cpu","Stk-Base","Stk-Sz","SP"); |
| for (qp = _PR_ACTIVE_LOCAL_THREADQ().next; |
| qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) { |
| thr = _PR_ACTIVE_THREAD_PTR(qp); |
| printf("%s 0x%-12x %-10s "," ",thr,_thr_state[thr->state]); |
| if (thr->state == _PR_LOCK_WAIT) |
| handle = thr->wait.lock; |
| else if (thr->state == _PR_COND_WAIT) |
| handle = thr->wait.cvar; |
| else |
| handle = NULL; |
| if (handle) |
| printf("0x%-10x ",handle); |
| else |
| printf("%-12s "," "); |
| printf("%-3d ",thr->cpu->id); |
| printf("0x%-8x ",thr->stack->stackBottom); |
| printf("0x%-8x ",thr->stack->stackSize); |
| printf("0x%-10x\n",thr->md.jb[JB_SP]); |
| } |
| |
| printf("\n%s %-s\n"," ","GLOBAL Threads"); |
| printf("%s %-s\n"," ","------ -------"); |
| printf("%s %-14s %-6s %-12s %-12s %-12s %-12s\n\n"," ","Thread", |
| "Pid","State","Wait-Handle", |
| "Stk-Base","Stk-Sz"); |
| |
| for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next; |
| qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) { |
| thr = _PR_ACTIVE_THREAD_PTR(qp); |
| if (thr->cpu != NULL) |
| continue; /* it is a cpu thread */ |
| printf("%s 0x%-12x %-6d "," ",thr,thr->md.id); |
| /* |
| * check if the sproc is still running |
| * first call prctl(PR_GETSHMASK,pid) to check if |
| * the process is part of the share group (the pid |
| * could have been recycled by the OS) |
| */ |
| if (prctl(PR_GETSHMASK,thr->md.id) < 0) { |
| printf("%-12s\n","TERMINATED"); |
| continue; |
| } |
| /* |
| * Now, check if the sproc terminated and is in zombie |
| * state |
| */ |
| sprintf(path,"/proc/pinfo/%s","00000"); |
| len = strlen(path); |
| sprintf(pidstr,"%d",thr->md.id); |
| len -= strlen(pidstr); |
| sprintf(path + len,"%s",pidstr); |
| fd = open(path,O_RDONLY); |
| if (fd >= 0) { |
| if (ioctl(fd, PIOCPSINFO, &pinfo) < 0) |
| printf("%-12s ","TERMINATED"); |
| else if (pinfo.pr_zomb) |
| printf("%-12s ","TERMINATED"); |
| else |
| printf("%-12s ",_thr_state[thr->state]); |
| close(fd); |
| } else { |
| printf("%-12s ","TERMINATED"); |
| } |
| |
| if (thr->state == _PR_LOCK_WAIT) |
| handle = thr->wait.lock; |
| else if (thr->state == _PR_COND_WAIT) |
| handle = thr->wait.cvar; |
| else |
| handle = NULL; |
| if (handle) |
| printf("%-12x ",handle); |
| else |
| printf("%-12s "," "); |
| printf("0x%-10x ",thr->stack->stackBottom); |
| printf("0x%-10x\n",thr->stack->stackSize); |
| } |
| |
| printf("\n%s %-s\n"," ","CPUs"); |
| printf("%s %-s\n"," ","----"); |
| printf("%s %-14s %-6s %-12s \n\n"," ","Id","Pid","State"); |
| |
| |
| for (qp = _PR_CPUQ().next; qp != &_PR_CPUQ(); qp = qp->next) { |
| cpu = _PR_CPU_PTR(qp); |
| printf("%s %-14d %-6d "," ",cpu->id,cpu->md.id); |
| /* |
| * check if the sproc is still running |
| * first call prctl(PR_GETSHMASK,pid) to check if |
| * the process is part of the share group (the pid |
| * could have been recycled by the OS) |
| */ |
| if (prctl(PR_GETSHMASK,cpu->md.id) < 0) { |
| printf("%-12s\n","TERMINATED"); |
| continue; |
| } |
| /* |
| * Now, check if the sproc terminated and is in zombie |
| * state |
| */ |
| sprintf(path,"/proc/pinfo/%s","00000"); |
| len = strlen(path); |
| sprintf(pidstr,"%d",cpu->md.id); |
| len -= strlen(pidstr); |
| sprintf(path + len,"%s",pidstr); |
| fd = open(path,O_RDONLY); |
| if (fd >= 0) { |
| if (ioctl(fd, PIOCPSINFO, &pinfo) < 0) |
| printf("%-12s\n","TERMINATED"); |
| else if (pinfo.pr_zomb) |
| printf("%-12s\n","TERMINATED"); |
| else |
| printf("%-12s\n","RUNNING"); |
| close(fd); |
| } else { |
| printf("%-12s\n","TERMINATED"); |
| } |
| |
| } |
| fflush(stdout); |
| } |
| #endif /* defined(_PR_PTHREADS) */ |
| |
| PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) |
| { |
| #if !defined(_PR_PTHREADS) |
| if (isCurrent) { |
| (void) setjmp(t->md.jb); |
| } |
| *np = sizeof(t->md.jb) / sizeof(PRWord); |
| return (PRWord *) (t->md.jb); |
| #else |
| *np = 0; |
| return NULL; |
| #endif |
| } |
| |
| void _MD_EarlyInit(void) |
| { |
| #if !defined(_PR_PTHREADS) |
| char *eval; |
| int fd; |
| extern int __ateachexit(void (*func)(void)); |
| |
| sigemptyset(&ints_off); |
| sigaddset(&ints_off, SIGALRM); |
| sigaddset(&ints_off, SIGIO); |
| sigaddset(&ints_off, SIGCLD); |
| |
| if (eval = getenv("_NSPR_TERMINATE_ON_ERROR")) |
| _nspr_terminate_on_error = (0 == atoi(eval) == 0) ? PR_FALSE : PR_TRUE; |
| |
| fd = open("/dev/zero",O_RDWR , 0); |
| if (fd < 0) { |
| perror("open /dev/zero failed"); |
| exit(1); |
| } |
| /* |
| * Set up the sproc private data area. |
| * This region exists at the same address, _nspr_sproc_private, for |
| * every sproc, but each sproc gets a private copy of the region. |
| */ |
| _nspr_sproc_private = (char*)mmap(0, _pr_pageSize, PROT_READ | PROT_WRITE, |
| MAP_PRIVATE| MAP_LOCAL, fd, 0); |
| if (_nspr_sproc_private == (void*)-1) { |
| perror("mmap /dev/zero failed"); |
| exit(1); |
| } |
| _MD_SET_SPROC_PID(getpid()); |
| close(fd); |
| __ateachexit(irix_detach_sproc); |
| #endif |
| _MD_IrixIntervalInit(); |
| } /* _MD_EarlyInit */ |
| |
| void _MD_IrixInit(void) |
| { |
| #if !defined(_PR_PTHREADS) |
| struct sigaction sigact; |
| PRThread *me = _PR_MD_CURRENT_THREAD(); |
| int rv; |
| |
| #ifdef _PR_HAVE_SGI_PRDA_PROCMASK |
| /* |
| * enable user-level processing of sigprocmask(); this is an undocumented |
| * feature available in Irix 6.2, 6.3, 6.4 and 6.5 |
| */ |
| __sgi_prda_procmask(USER_LEVEL); |
| #endif |
| |
| /* |
| * set up SIGUSR1 handler; this is used to save state |
| * during PR_SuspendAll |
| */ |
| sigact.sa_handler = save_context_and_block; |
| sigact.sa_flags = SA_RESTART; |
| sigact.sa_mask = ints_off; |
| sigaction(SIGUSR1, &sigact, 0); |
| |
| /* |
| * Change the name of the core file from core to core.pid, |
| * This is inherited by the sprocs created by this process |
| */ |
| #ifdef PR_COREPID |
| prctl(PR_COREPID, 0, 1); |
| #endif |
| /* |
| * Irix-specific terminate on error processing |
| */ |
| /* |
| * PR_SETABORTSIG is a new command implemented in a patch to |
| * Irix 6.2, 6.3 and 6.4. This causes a signal to be sent to all |
| * sprocs in the process when one of them terminates abnormally |
| * |
| */ |
| if (prctl(PR_SETABORTSIG, SIGKILL) < 0) { |
| /* |
| * if (errno == EINVAL) |
| * |
| * PR_SETABORTSIG not supported under this OS. |
| * You may want to get a recent kernel rollup patch that |
| * supports this feature. |
| * |
| */ |
| } |
| /* |
| * PR_SETEXITSIG - send the SIGCLD signal to the parent |
| * sproc when any sproc terminates |
| * |
| * This is used to cause the entire application to |
| * terminate when any sproc terminates abnormally by |
| * receipt of a SIGSEGV, SIGBUS or SIGABRT signal. |
| * If this is not done, the application may seem |
| * "hung" to the user because the other sprocs may be |
| * waiting for resources held by the |
| * abnormally-terminating sproc. |
| */ |
| prctl(PR_SETEXITSIG, 0); |
| |
| sigact.sa_handler = sigchld_handler; |
| sigact.sa_flags = SA_RESTART; |
| sigact.sa_mask = ints_off; |
| sigaction(SIGCLD, &sigact, NULL); |
| |
| /* |
| * setup stack fields for the primordial thread |
| */ |
| me->stack->stackSize = prctl(PR_GETSTACKSIZE); |
| me->stack->stackBottom = me->stack->stackTop - me->stack->stackSize; |
| |
| rv = pipe(_pr_irix_primoridal_cpu_fd); |
| PR_ASSERT(rv == 0); |
| #ifndef _PR_USE_POLL |
| _PR_IOQ_MAX_OSFD(me->cpu) = _pr_irix_primoridal_cpu_fd[0]; |
| FD_SET(_pr_irix_primoridal_cpu_fd[0], &_PR_FD_READ_SET(me->cpu)); |
| #endif |
| |
| libc_handle = dlopen("libc.so",RTLD_NOW); |
| PR_ASSERT(libc_handle != NULL); |
| libc_exit = (void (*)(int)) dlsym(libc_handle, "exit"); |
| PR_ASSERT(libc_exit != NULL); |
| /* dlclose(libc_handle); */ |
| |
| #endif /* _PR_PTHREADS */ |
| |
| _PR_UnixInit(); |
| } |
| |
| /**************************************************************************/ |
| /************** code and such for NSPR 2.0's interval times ***************/ |
| /**************************************************************************/ |
| |
| #define PR_PSEC_PER_SEC 1000000000000ULL /* 10^12 */ |
| |
| #ifndef SGI_CYCLECNTR_SIZE |
| #define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */ |
| #endif |
| |
| static PRIntn mmem_fd = -1; |
| static PRIntn clock_width = 0; |
| static void *iotimer_addr = NULL; |
| static PRUint32 pr_clock_mask = 0; |
| static PRUint32 pr_clock_shift = 0; |
| static PRIntervalTime pr_ticks = 0; |
| static PRUint32 pr_clock_granularity = 1; |
| static PRUint32 pr_previous = 0, pr_residual = 0; |
| static PRUint32 pr_ticks_per_second = 0; |
| |
| extern PRIntervalTime _PR_UNIX_GetInterval(void); |
| extern PRIntervalTime _PR_UNIX_TicksPerSecond(void); |
| |
| static void _MD_IrixIntervalInit(void) |
| { |
| /* |
| * As much as I would like, the service available through this |
| * interface on R3000's (aka, IP12) just isn't going to make it. |
| * The register is only 24 bits wide, and rolls over at a verocious |
| * rate. |
| */ |
| PRUint32 one_tick = 0; |
| struct utsname utsinfo; |
| uname(&utsinfo); |
| if ((strncmp("IP12", utsinfo.machine, 4) != 0) |
| && ((mmem_fd = open("/dev/mmem", O_RDONLY)) != -1)) |
| { |
| int poffmask = getpagesize() - 1; |
| __psunsigned_t phys_addr, raddr, cycleval; |
| |
| phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval); |
| raddr = phys_addr & ~poffmask; |
| iotimer_addr = mmap( |
| 0, poffmask, PROT_READ, MAP_PRIVATE, mmem_fd, (__psint_t)raddr); |
| |
| clock_width = syssgi(SGI_CYCLECNTR_SIZE); |
| if (clock_width < 0) |
| { |
| /* |
| * We must be executing on a 6.0 or earlier system, since the |
| * SGI_CYCLECNTR_SIZE call is not supported. |
| * |
| * The only pre-6.1 platforms with 64-bit counters are |
| * IP19 and IP21 (Challenge, PowerChallenge, Onyx). |
| */ |
| if (!strncmp(utsinfo.machine, "IP19", 4) || |
| !strncmp(utsinfo.machine, "IP21", 4)) |
| clock_width = 64; |
| else |
| clock_width = 32; |
| } |
| |
| /* |
| * 'cycleval' is picoseconds / increment of the counter. |
| * I'm pushing for a tick to be 100 microseconds, 10^(-4). |
| * That leaves 10^(-8) left over, or 10^8 / cycleval. |
| * Did I do that right? |
| */ |
| |
| one_tick = 100000000UL / cycleval ; /* 100 microseconds */ |
| |
| while (0 != one_tick) |
| { |
| pr_clock_shift += 1; |
| one_tick = one_tick >> 1; |
| pr_clock_granularity = pr_clock_granularity << 1; |
| } |
| pr_clock_mask = pr_clock_granularity - 1; /* to make a mask out of it */ |
| pr_ticks_per_second = PR_PSEC_PER_SEC |
| / ((PRUint64)pr_clock_granularity * (PRUint64)cycleval); |
| |
| iotimer_addr = (void*) |
| ((__psunsigned_t)iotimer_addr + (phys_addr & poffmask)); |
| } |
| else |
| { |
| pr_ticks_per_second = _PR_UNIX_TicksPerSecond(); |
| } |
| } /* _MD_IrixIntervalInit */ |
| |
| PRIntervalTime _MD_IrixIntervalPerSec(void) |
| { |
| return pr_ticks_per_second; |
| } |
| |
| PRIntervalTime _MD_IrixGetInterval(void) |
| { |
| if (mmem_fd != -1) |
| { |
| if (64 == clock_width) |
| { |
| PRUint64 temp = *(PRUint64*)iotimer_addr; |
| pr_ticks = (PRIntervalTime)(temp >> pr_clock_shift); |
| } |
| else |
| { |
| PRIntervalTime ticks = pr_ticks; |
| PRUint32 now = *(PRUint32*)iotimer_addr, temp; |
| PRUint32 residual = pr_residual, previous = pr_previous; |
| |
| temp = now - previous + residual; |
| residual = temp & pr_clock_mask; |
| ticks += temp >> pr_clock_shift; |
| |
| pr_previous = now; |
| pr_residual = residual; |
| pr_ticks = ticks; |
| } |
| } |
| else |
| { |
| /* |
| * No fast access. Use the time of day clock. This isn't the |
| * right answer since this clock can get set back, tick at odd |
| * rates, and it's expensive to acqurie. |
| */ |
| pr_ticks = _PR_UNIX_GetInterval(); |
| } |
| return pr_ticks; |
| } /* _MD_IrixGetInterval */ |
| |