📄 irix.c
字号:
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* * 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 Netscape are * Copyright (C) 1998-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#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 voidsigchld_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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -