nsprpub/pr/src/md/unix/irix.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nsprpub/pr/src/md/unix/irix.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1648 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "primpl.h"
    1.10 +
    1.11 +#include <signal.h>
    1.12 +
    1.13 +#include <sys/types.h>
    1.14 +#include <fcntl.h>
    1.15 +#include <unistd.h>
    1.16 +#include <string.h>
    1.17 +#include <sys/mman.h>
    1.18 +#include <sys/syssgi.h>
    1.19 +#include <sys/time.h>
    1.20 +#include <sys/immu.h>
    1.21 +#include <sys/utsname.h>
    1.22 +#include <sys/sysmp.h>
    1.23 +#include <sys/pda.h>
    1.24 +#include <sys/prctl.h>
    1.25 +#include <sys/wait.h>
    1.26 +#include <sys/resource.h>
    1.27 +#include <sys/procfs.h>
    1.28 +#include <task.h>
    1.29 +#include <dlfcn.h>
    1.30 +
    1.31 +static void _MD_IrixIntervalInit(void);
    1.32 +
    1.33 +#if defined(_PR_PTHREADS)
    1.34 +/*
    1.35 + * for compatibility with classic nspr
    1.36 + */
    1.37 +void _PR_IRIX_CHILD_PROCESS()
    1.38 +{
    1.39 +}
    1.40 +#else  /* defined(_PR_PTHREADS) */
    1.41 +
    1.42 +static void irix_detach_sproc(void);
    1.43 +char *_nspr_sproc_private;    /* ptr. to private region in every sproc */
    1.44 +
    1.45 +extern PRUintn    _pr_numCPU;
    1.46 +
    1.47 +typedef struct nspr_arena {
    1.48 +	PRCList links;
    1.49 +	usptr_t *usarena;
    1.50 +} nspr_arena;
    1.51 +
    1.52 +#define ARENA_PTR(qp) \
    1.53 +	((nspr_arena *) ((char*) (qp) - offsetof(nspr_arena , links)))
    1.54 +
    1.55 +static usptr_t *alloc_new_arena(void);
    1.56 +
    1.57 +PRCList arena_list = PR_INIT_STATIC_CLIST(&arena_list);
    1.58 +ulock_t arena_list_lock;
    1.59 +nspr_arena first_arena;
    1.60 +int	_nspr_irix_arena_cnt = 1;
    1.61 +
    1.62 +PRCList sproc_list = PR_INIT_STATIC_CLIST(&sproc_list);
    1.63 +ulock_t sproc_list_lock;
    1.64 +
    1.65 +typedef struct sproc_data {
    1.66 +	void (*entry) (void *, size_t);
    1.67 +	unsigned inh;
    1.68 +	void *arg;
    1.69 +	caddr_t sp;
    1.70 +	size_t len;
    1.71 +	int *pid;
    1.72 +	int creator_pid;
    1.73 +} sproc_data;
    1.74 +
    1.75 +typedef struct sproc_params {
    1.76 +	PRCList links;
    1.77 +	sproc_data sd;
    1.78 +} sproc_params;
    1.79 +
    1.80 +#define SPROC_PARAMS_PTR(qp) \
    1.81 +	((sproc_params *) ((char*) (qp) - offsetof(sproc_params , links)))
    1.82 +
    1.83 +long	_nspr_irix_lock_cnt = 0;
    1.84 +long	_nspr_irix_sem_cnt = 0;
    1.85 +long	_nspr_irix_pollsem_cnt = 0;
    1.86 +
    1.87 +usptr_t *_pr_usArena;
    1.88 +ulock_t _pr_heapLock;
    1.89 +
    1.90 +usema_t *_pr_irix_exit_sem;
    1.91 +PRInt32 _pr_irix_exit_now = 0;
    1.92 +PRInt32 _pr_irix_process_exit_code = 0;	/* exit code for PR_ProcessExit */
    1.93 +PRInt32 _pr_irix_process_exit = 0; /* process exiting due to call to
    1.94 +										   PR_ProcessExit */
    1.95 +
    1.96 +int _pr_irix_primoridal_cpu_fd[2] = { -1, -1 };
    1.97 +static void (*libc_exit)(int) = NULL;
    1.98 +static void *libc_handle = NULL;
    1.99 +
   1.100 +#define _NSPR_DEF_INITUSERS		100	/* default value of CONF_INITUSERS */
   1.101 +#define _NSPR_DEF_INITSIZE		(4 * 1024 * 1024)	/* 4 MB */
   1.102 +
   1.103 +int _irix_initusers = _NSPR_DEF_INITUSERS;
   1.104 +int _irix_initsize = _NSPR_DEF_INITSIZE;
   1.105 +
   1.106 +PRIntn _pr_io_in_progress, _pr_clock_in_progress;
   1.107 +
   1.108 +PRInt32 _pr_md_irix_sprocs_created, _pr_md_irix_sprocs_failed;
   1.109 +PRInt32 _pr_md_irix_sprocs = 1;
   1.110 +PRCList _pr_md_irix_sproc_list =
   1.111 +PR_INIT_STATIC_CLIST(&_pr_md_irix_sproc_list);
   1.112 +
   1.113 +sigset_t ints_off;
   1.114 +extern sigset_t timer_set;
   1.115 +
   1.116 +#if !defined(PR_SETABORTSIG)
   1.117 +#define PR_SETABORTSIG 18
   1.118 +#endif
   1.119 +/*
   1.120 + * terminate the entire application if any sproc exits abnormally
   1.121 + */
   1.122 +PRBool _nspr_terminate_on_error = PR_TRUE;
   1.123 +
   1.124 +/*
   1.125 + * exported interface to set the shared arena parameters
   1.126 + */
   1.127 +void _PR_Irix_Set_Arena_Params(PRInt32 initusers, PRInt32 initsize)
   1.128 +{
   1.129 +    _irix_initusers = initusers;
   1.130 +    _irix_initsize = initsize;
   1.131 +}
   1.132 +
   1.133 +static usptr_t *alloc_new_arena()
   1.134 +{
   1.135 +    return(usinit("/dev/zero"));
   1.136 +}
   1.137 +
   1.138 +static PRStatus new_poll_sem(struct _MDThread *mdthr, int val)
   1.139 +{
   1.140 +PRIntn _is;
   1.141 +PRStatus rv = PR_SUCCESS;
   1.142 +usema_t *sem = NULL;
   1.143 +PRCList *qp;
   1.144 +nspr_arena *arena;
   1.145 +usptr_t *irix_arena;
   1.146 +PRThread *me = _MD_GET_ATTACHED_THREAD();	
   1.147 +
   1.148 +	if (me && !_PR_IS_NATIVE_THREAD(me))
   1.149 +		_PR_INTSOFF(_is); 
   1.150 +	_PR_LOCK(arena_list_lock);
   1.151 +	for (qp = arena_list.next; qp != &arena_list; qp = qp->next) {
   1.152 +		arena = ARENA_PTR(qp);
   1.153 +		sem = usnewpollsema(arena->usarena, val);
   1.154 +		if (sem != NULL) {
   1.155 +			mdthr->cvar_pollsem = sem;
   1.156 +			mdthr->pollsem_arena = arena->usarena;
   1.157 +			break;
   1.158 +		}
   1.159 +	}
   1.160 +	if (sem == NULL) {
   1.161 +		/*
   1.162 +		 * If no space left in the arena allocate a new one.
   1.163 +		 */
   1.164 +		if (errno == ENOMEM) {
   1.165 +			arena = PR_NEWZAP(nspr_arena);
   1.166 +			if (arena != NULL) {
   1.167 +				irix_arena = alloc_new_arena();
   1.168 +				if (irix_arena) {
   1.169 +					PR_APPEND_LINK(&arena->links, &arena_list);
   1.170 +					_nspr_irix_arena_cnt++;
   1.171 +					arena->usarena = irix_arena;
   1.172 +					sem = usnewpollsema(arena->usarena, val);
   1.173 +					if (sem != NULL) {
   1.174 +						mdthr->cvar_pollsem = sem;
   1.175 +						mdthr->pollsem_arena = arena->usarena;
   1.176 +					} else
   1.177 +						rv = PR_FAILURE;
   1.178 +				} else {
   1.179 +					PR_DELETE(arena);
   1.180 +					rv = PR_FAILURE;
   1.181 +				}
   1.182 +
   1.183 +			} else
   1.184 +				rv = PR_FAILURE;
   1.185 +		} else
   1.186 +			rv = PR_FAILURE;
   1.187 +	}
   1.188 +	_PR_UNLOCK(arena_list_lock);
   1.189 +	if (me && !_PR_IS_NATIVE_THREAD(me))
   1.190 +		_PR_FAST_INTSON(_is);
   1.191 +	if (rv == PR_SUCCESS)
   1.192 +		_MD_ATOMIC_INCREMENT(&_nspr_irix_pollsem_cnt);
   1.193 +	return rv;
   1.194 +}
   1.195 +
   1.196 +static void free_poll_sem(struct _MDThread *mdthr)
   1.197 +{
   1.198 +PRIntn _is;
   1.199 +PRThread *me = _MD_GET_ATTACHED_THREAD();	
   1.200 +
   1.201 +	if (me && !_PR_IS_NATIVE_THREAD(me))
   1.202 +		_PR_INTSOFF(_is); 
   1.203 +	usfreepollsema(mdthr->cvar_pollsem, mdthr->pollsem_arena);
   1.204 +	if (me && !_PR_IS_NATIVE_THREAD(me))
   1.205 +		_PR_FAST_INTSON(_is);
   1.206 +	_MD_ATOMIC_DECREMENT(&_nspr_irix_pollsem_cnt);
   1.207 +}
   1.208 +
   1.209 +static PRStatus new_lock(struct _MDLock *lockp)
   1.210 +{
   1.211 +PRIntn _is;
   1.212 +PRStatus rv = PR_SUCCESS;
   1.213 +ulock_t lock = NULL;
   1.214 +PRCList *qp;
   1.215 +nspr_arena *arena;
   1.216 +usptr_t *irix_arena;
   1.217 +PRThread *me = _MD_GET_ATTACHED_THREAD();	
   1.218 +
   1.219 +	if (me && !_PR_IS_NATIVE_THREAD(me))
   1.220 +		_PR_INTSOFF(_is); 
   1.221 +	_PR_LOCK(arena_list_lock);
   1.222 +	for (qp = arena_list.next; qp != &arena_list; qp = qp->next) {
   1.223 +		arena = ARENA_PTR(qp);
   1.224 +		lock = usnewlock(arena->usarena);
   1.225 +		if (lock != NULL) {
   1.226 +			lockp->lock = lock;
   1.227 +			lockp->arena = arena->usarena;
   1.228 +			break;
   1.229 +		}
   1.230 +	}
   1.231 +	if (lock == NULL) {
   1.232 +		/*
   1.233 +		 * If no space left in the arena allocate a new one.
   1.234 +		 */
   1.235 +		if (errno == ENOMEM) {
   1.236 +			arena = PR_NEWZAP(nspr_arena);
   1.237 +			if (arena != NULL) {
   1.238 +				irix_arena = alloc_new_arena();
   1.239 +				if (irix_arena) {
   1.240 +					PR_APPEND_LINK(&arena->links, &arena_list);
   1.241 +					_nspr_irix_arena_cnt++;
   1.242 +					arena->usarena = irix_arena;
   1.243 +					lock = usnewlock(irix_arena);
   1.244 +					if (lock != NULL) {
   1.245 +						lockp->lock = lock;
   1.246 +						lockp->arena = arena->usarena;
   1.247 +					} else
   1.248 +						rv = PR_FAILURE;
   1.249 +				} else {
   1.250 +					PR_DELETE(arena);
   1.251 +					rv = PR_FAILURE;
   1.252 +				}
   1.253 +
   1.254 +			} else
   1.255 +				rv = PR_FAILURE;
   1.256 +		} else
   1.257 +			rv = PR_FAILURE;
   1.258 +	}
   1.259 +	_PR_UNLOCK(arena_list_lock);
   1.260 +	if (me && !_PR_IS_NATIVE_THREAD(me))
   1.261 +		_PR_FAST_INTSON(_is);
   1.262 +	if (rv == PR_SUCCESS)
   1.263 +		_MD_ATOMIC_INCREMENT(&_nspr_irix_lock_cnt);
   1.264 +	return rv;
   1.265 +}
   1.266 +
   1.267 +static void free_lock(struct _MDLock *lockp)
   1.268 +{
   1.269 +PRIntn _is;
   1.270 +PRThread *me = _MD_GET_ATTACHED_THREAD();	
   1.271 +
   1.272 +	if (me && !_PR_IS_NATIVE_THREAD(me))
   1.273 +		_PR_INTSOFF(_is); 
   1.274 +	usfreelock(lockp->lock, lockp->arena);
   1.275 +	if (me && !_PR_IS_NATIVE_THREAD(me))
   1.276 +		_PR_FAST_INTSON(_is);
   1.277 +	_MD_ATOMIC_DECREMENT(&_nspr_irix_lock_cnt);
   1.278 +}
   1.279 +
   1.280 +void _MD_FREE_LOCK(struct _MDLock *lockp)
   1.281 +{
   1.282 +	PRIntn _is;
   1.283 +	PRThread *me = _MD_GET_ATTACHED_THREAD();	
   1.284 +
   1.285 +	if (me && !_PR_IS_NATIVE_THREAD(me))
   1.286 +		_PR_INTSOFF(_is); 
   1.287 +	free_lock(lockp);
   1.288 +	if (me && !_PR_IS_NATIVE_THREAD(me))
   1.289 +		_PR_FAST_INTSON(_is);
   1.290 +}
   1.291 +
   1.292 +/*
   1.293 + * _MD_get_attached_thread
   1.294 + *		Return the thread pointer of the current thread if it is attached.
   1.295 + *
   1.296 + *		This function is needed for Irix because the thread-local-storage is
   1.297 + *		implemented by mmapin'g a page with the MAP_LOCAL flag. This causes the
   1.298 + *		sproc-private page to inherit contents of the page of the caller of sproc().
   1.299 + */
   1.300 +PRThread *_MD_get_attached_thread(void)
   1.301 +{
   1.302 +
   1.303 +	if (_MD_GET_SPROC_PID() == get_pid())
   1.304 +		return _MD_THIS_THREAD();
   1.305 +	else
   1.306 +		return 0;
   1.307 +}
   1.308 +
   1.309 +/*
   1.310 + * _MD_get_current_thread
   1.311 + *		Return the thread pointer of the current thread (attaching it if
   1.312 + *		necessary)
   1.313 + */
   1.314 +PRThread *_MD_get_current_thread(void)
   1.315 +{
   1.316 +PRThread *me;
   1.317 +
   1.318 +	me = _MD_GET_ATTACHED_THREAD();
   1.319 +    if (NULL == me) {
   1.320 +        me = _PRI_AttachThread(
   1.321 +            PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0);
   1.322 +    }
   1.323 +    PR_ASSERT(me != NULL);
   1.324 +	return(me);
   1.325 +}
   1.326 +
   1.327 +/*
   1.328 + * irix_detach_sproc
   1.329 + *		auto-detach a sproc when it exits
   1.330 + */
   1.331 +void irix_detach_sproc(void)
   1.332 +{
   1.333 +PRThread *me;
   1.334 +
   1.335 +	me = _MD_GET_ATTACHED_THREAD();
   1.336 +	if ((me != NULL) && (me->flags & _PR_ATTACHED)) {
   1.337 +		_PRI_DetachThread();
   1.338 +	}
   1.339 +}
   1.340 +
   1.341 +
   1.342 +PRStatus _MD_NEW_LOCK(struct _MDLock *lockp)
   1.343 +{
   1.344 +    PRStatus rv;
   1.345 +    PRIntn is;
   1.346 +    PRThread *me = _MD_GET_ATTACHED_THREAD();	
   1.347 +
   1.348 +	if (me && !_PR_IS_NATIVE_THREAD(me))
   1.349 +		_PR_INTSOFF(is);
   1.350 +	rv = new_lock(lockp);
   1.351 +	if (me && !_PR_IS_NATIVE_THREAD(me))
   1.352 +		_PR_FAST_INTSON(is);
   1.353 +	return rv;
   1.354 +}
   1.355 +
   1.356 +static void
   1.357 +sigchld_handler(int sig)
   1.358 +{
   1.359 +    pid_t pid;
   1.360 +    int status;
   1.361 +
   1.362 +    /*
   1.363 +     * If an sproc exited abnormally send a SIGKILL signal to all the
   1.364 +     * sprocs in the process to terminate the application
   1.365 +     */
   1.366 +    while ((pid = waitpid(0, &status, WNOHANG)) > 0) {
   1.367 +        if (WIFSIGNALED(status) && ((WTERMSIG(status) == SIGSEGV) ||
   1.368 +            (WTERMSIG(status) == SIGBUS) ||
   1.369 +            (WTERMSIG(status) == SIGABRT) ||
   1.370 +            (WTERMSIG(status) == SIGILL))) {
   1.371 +
   1.372 +				prctl(PR_SETEXITSIG, SIGKILL);
   1.373 +				_exit(status);
   1.374 +			}
   1.375 +    }
   1.376 +}
   1.377 +
   1.378 +static void save_context_and_block(int sig)
   1.379 +{
   1.380 +PRThread *me = _PR_MD_CURRENT_THREAD();
   1.381 +_PRCPU *cpu = _PR_MD_CURRENT_CPU();
   1.382 +
   1.383 +	/*
   1.384 +	 * save context
   1.385 +	 */
   1.386 +	(void) setjmp(me->md.jb);
   1.387 +	/*
   1.388 +	 * unblock the suspending thread
   1.389 +	 */
   1.390 +	if (me->cpu) {
   1.391 +		/*
   1.392 +		 * I am a cpu thread, not a user-created GLOBAL thread
   1.393 +		 */
   1.394 +		unblockproc(cpu->md.suspending_id);	
   1.395 +	} else {
   1.396 +		unblockproc(me->md.suspending_id);	
   1.397 +	}
   1.398 +	/*
   1.399 +	 * now, block current thread
   1.400 +	 */
   1.401 +	blockproc(getpid());
   1.402 +}
   1.403 +
   1.404 +/*
   1.405 +** The irix kernel has a bug in it which causes async connect's which are
   1.406 +** interrupted by a signal to fail terribly (EADDRINUSE is returned). 
   1.407 +** We work around the bug by blocking signals during the async connect
   1.408 +** attempt.
   1.409 +*/
   1.410 +PRInt32 _MD_irix_connect(
   1.411 +    PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen, PRIntervalTime timeout)
   1.412 +{
   1.413 +    PRInt32 rv;
   1.414 +    sigset_t oldset;
   1.415 +
   1.416 +    sigprocmask(SIG_BLOCK, &ints_off, &oldset);
   1.417 +    rv = connect(osfd, addr, addrlen);
   1.418 +    sigprocmask(SIG_SETMASK, &oldset, 0);
   1.419 +
   1.420 +    return(rv);
   1.421 +}
   1.422 +
   1.423 +#include "prprf.h"
   1.424 +
   1.425 +/********************************************************************/
   1.426 +/********************************************************************/
   1.427 +/*************** Various thread like things for IRIX ****************/
   1.428 +/********************************************************************/
   1.429 +/********************************************************************/
   1.430 +
   1.431 +void *_MD_GetSP(PRThread *t)
   1.432 +{
   1.433 +    PRThread *me = _PR_MD_CURRENT_THREAD();
   1.434 +    void *sp;
   1.435 +
   1.436 +    if (me == t)
   1.437 +        (void) setjmp(t->md.jb);
   1.438 +
   1.439 +    sp = (void *)(t->md.jb[JB_SP]);
   1.440 +    PR_ASSERT((sp >= (void *) t->stack->stackBottom) &&
   1.441 +        (sp <= (void *) (t->stack->stackBottom + t->stack->stackSize)));
   1.442 +    return(sp);
   1.443 +}
   1.444 +
   1.445 +void _MD_InitLocks()
   1.446 +{
   1.447 +    char buf[200];
   1.448 +    char *init_users, *init_size;
   1.449 +
   1.450 +    PR_snprintf(buf, sizeof(buf), "/dev/zero");
   1.451 +
   1.452 +    if (init_users = getenv("_NSPR_IRIX_INITUSERS"))
   1.453 +        _irix_initusers = atoi(init_users);
   1.454 +
   1.455 +    if (init_size = getenv("_NSPR_IRIX_INITSIZE"))
   1.456 +        _irix_initsize = atoi(init_size);
   1.457 +
   1.458 +    usconfig(CONF_INITUSERS, _irix_initusers);
   1.459 +    usconfig(CONF_INITSIZE, _irix_initsize);
   1.460 +    usconfig(CONF_AUTOGROW, 1);
   1.461 +    usconfig(CONF_AUTORESV, 1);
   1.462 +	if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0) {
   1.463 +		perror("PR_Init: unable to config mutex arena");
   1.464 +		exit(-1);
   1.465 +	}
   1.466 +
   1.467 +    _pr_usArena = usinit(buf);
   1.468 +    if (!_pr_usArena) {
   1.469 +        fprintf(stderr,
   1.470 +            "PR_Init: Error - unable to create lock/monitor arena\n");
   1.471 +        exit(-1);
   1.472 +    }
   1.473 +    _pr_heapLock = usnewlock(_pr_usArena);
   1.474 +	_nspr_irix_lock_cnt++;
   1.475 +
   1.476 +    arena_list_lock = usnewlock(_pr_usArena);
   1.477 +	_nspr_irix_lock_cnt++;
   1.478 +
   1.479 +    sproc_list_lock = usnewlock(_pr_usArena);
   1.480 +	_nspr_irix_lock_cnt++;
   1.481 +
   1.482 +	_pr_irix_exit_sem = usnewsema(_pr_usArena, 0);
   1.483 +	_nspr_irix_sem_cnt = 1;
   1.484 +
   1.485 +	first_arena.usarena = _pr_usArena;
   1.486 +	PR_INIT_CLIST(&first_arena.links);
   1.487 +	PR_APPEND_LINK(&first_arena.links, &arena_list);
   1.488 +}
   1.489 +
   1.490 +/* _PR_IRIX_CHILD_PROCESS is a private API for Server group */
   1.491 +void _PR_IRIX_CHILD_PROCESS()
   1.492 +{
   1.493 +extern PRUint32 _pr_global_threads;
   1.494 +
   1.495 +    PR_ASSERT(_PR_MD_CURRENT_CPU() == _pr_primordialCPU);
   1.496 +    PR_ASSERT(_pr_numCPU == 1);
   1.497 +    PR_ASSERT(_pr_global_threads == 0);
   1.498 +    /*
   1.499 +     * save the new pid
   1.500 +     */
   1.501 +    _pr_primordialCPU->md.id = getpid();
   1.502 +	_MD_SET_SPROC_PID(getpid());	
   1.503 +}
   1.504 +
   1.505 +static PRStatus pr_cvar_wait_sem(PRThread *thread, PRIntervalTime timeout)
   1.506 +{
   1.507 +    int rv;
   1.508 +
   1.509 +#ifdef _PR_USE_POLL
   1.510 +	struct pollfd pfd;
   1.511 +	int msecs;
   1.512 +
   1.513 +	if (timeout == PR_INTERVAL_NO_TIMEOUT)
   1.514 +		msecs = -1;
   1.515 +	else
   1.516 +		msecs  = PR_IntervalToMilliseconds(timeout);
   1.517 +#else
   1.518 +    struct timeval tv, *tvp;
   1.519 +    fd_set rd;
   1.520 +
   1.521 +	if(timeout == PR_INTERVAL_NO_TIMEOUT)
   1.522 +		tvp = NULL;
   1.523 +	else {
   1.524 +		tv.tv_sec = PR_IntervalToSeconds(timeout);
   1.525 +		tv.tv_usec = PR_IntervalToMicroseconds(
   1.526 +		timeout - PR_SecondsToInterval(tv.tv_sec));
   1.527 +		tvp = &tv;
   1.528 +	}
   1.529 +	FD_ZERO(&rd);
   1.530 +	FD_SET(thread->md.cvar_pollsemfd, &rd);
   1.531 +#endif
   1.532 +
   1.533 +    /*
   1.534 +     * call uspsema only if a previous select call on this semaphore
   1.535 +     * did not timeout
   1.536 +     */
   1.537 +    if (!thread->md.cvar_pollsem_select) {
   1.538 +        rv = _PR_WAIT_SEM(thread->md.cvar_pollsem);
   1.539 +		PR_ASSERT(rv >= 0);
   1.540 +	} else
   1.541 +        rv = 0;
   1.542 +again:
   1.543 +    if(!rv) {
   1.544 +#ifdef _PR_USE_POLL
   1.545 +		pfd.events = POLLIN;
   1.546 +		pfd.fd = thread->md.cvar_pollsemfd;
   1.547 +		rv = _MD_POLL(&pfd, 1, msecs);
   1.548 +#else
   1.549 +		rv = _MD_SELECT(thread->md.cvar_pollsemfd + 1, &rd, NULL,NULL,tvp);
   1.550 +#endif
   1.551 +        if ((rv == -1) && (errno == EINTR)) {
   1.552 +			rv = 0;
   1.553 +			goto again;
   1.554 +		}
   1.555 +		PR_ASSERT(rv >= 0);
   1.556 +	}
   1.557 +
   1.558 +    if (rv > 0) {
   1.559 +        /*
   1.560 +         * acquired the semaphore, call uspsema next time
   1.561 +         */
   1.562 +        thread->md.cvar_pollsem_select = 0;
   1.563 +        return PR_SUCCESS;
   1.564 +    } else {
   1.565 +        /*
   1.566 +         * select timed out; must call select, not uspsema, when trying
   1.567 +         * to acquire the semaphore the next time
   1.568 +         */
   1.569 +        thread->md.cvar_pollsem_select = 1;
   1.570 +        return PR_FAILURE;
   1.571 +    }
   1.572 +}
   1.573 +
   1.574 +PRStatus _MD_wait(PRThread *thread, PRIntervalTime ticks)
   1.575 +{
   1.576 +    if ( thread->flags & _PR_GLOBAL_SCOPE ) {
   1.577 +	_MD_CHECK_FOR_EXIT();
   1.578 +        if (pr_cvar_wait_sem(thread, ticks) == PR_FAILURE) {
   1.579 +	    _MD_CHECK_FOR_EXIT();
   1.580 +            /*
   1.581 +             * wait timed out
   1.582 +             */
   1.583 +            _PR_THREAD_LOCK(thread);
   1.584 +            if (thread->wait.cvar) {
   1.585 +                /*
   1.586 +                 * The thread will remove itself from the waitQ
   1.587 +                 * of the cvar in _PR_WaitCondVar
   1.588 +                 */
   1.589 +                thread->wait.cvar = NULL;
   1.590 +                thread->state =  _PR_RUNNING;
   1.591 +                _PR_THREAD_UNLOCK(thread);
   1.592 +            }  else {
   1.593 +                _PR_THREAD_UNLOCK(thread);
   1.594 +                /*
   1.595 +             * This thread was woken up by a notifying thread
   1.596 +             * at the same time as a timeout; so, consume the
   1.597 +             * extra post operation on the semaphore
   1.598 +             */
   1.599 +	        _MD_CHECK_FOR_EXIT();
   1.600 +            pr_cvar_wait_sem(thread, PR_INTERVAL_NO_TIMEOUT);
   1.601 +            }
   1.602 +	    _MD_CHECK_FOR_EXIT();
   1.603 +        }
   1.604 +    } else {
   1.605 +        _PR_MD_SWITCH_CONTEXT(thread);
   1.606 +    }
   1.607 +    return PR_SUCCESS;
   1.608 +}
   1.609 +
   1.610 +PRStatus _MD_WakeupWaiter(PRThread *thread)
   1.611 +{
   1.612 +    PRThread *me = _PR_MD_CURRENT_THREAD();
   1.613 +    PRIntn is;
   1.614 +
   1.615 +	PR_ASSERT(_pr_md_idle_cpus >= 0);
   1.616 +    if (thread == NULL) {
   1.617 +		if (_pr_md_idle_cpus)
   1.618 +        	_MD_Wakeup_CPUs();
   1.619 +    } else if (!_PR_IS_NATIVE_THREAD(thread)) {
   1.620 +		if (_pr_md_idle_cpus)
   1.621 +       		_MD_Wakeup_CPUs();
   1.622 +    } else {
   1.623 +		PR_ASSERT(_PR_IS_NATIVE_THREAD(thread));
   1.624 +		if (!_PR_IS_NATIVE_THREAD(me))
   1.625 +			_PR_INTSOFF(is);
   1.626 +		_MD_CVAR_POST_SEM(thread);
   1.627 +		if (!_PR_IS_NATIVE_THREAD(me))
   1.628 +			_PR_FAST_INTSON(is);
   1.629 +    } 
   1.630 +    return PR_SUCCESS;
   1.631 +}
   1.632 +
   1.633 +void create_sproc (void (*entry) (void *, size_t), unsigned inh,
   1.634 +					void *arg, caddr_t sp, size_t len, int *pid)
   1.635 +{
   1.636 +sproc_params sparams;
   1.637 +char data;
   1.638 +int rv;
   1.639 +PRThread *me = _PR_MD_CURRENT_THREAD();
   1.640 +
   1.641 +	if (!_PR_IS_NATIVE_THREAD(me) && (_PR_MD_CURRENT_CPU()->id == 0)) {
   1.642 +		*pid = sprocsp(entry,		/* startup func		*/
   1.643 +						inh,        /* attribute flags	*/
   1.644 +						arg,     	/* thread param		*/
   1.645 +						sp,         /* stack address	*/
   1.646 +						len);       /* stack size		*/
   1.647 +	} else {
   1.648 +		sparams.sd.entry = entry;
   1.649 +		sparams.sd.inh = inh;
   1.650 +		sparams.sd.arg = arg;
   1.651 +		sparams.sd.sp = sp;
   1.652 +		sparams.sd.len = len;
   1.653 +		sparams.sd.pid = pid;
   1.654 +		sparams.sd.creator_pid = getpid();
   1.655 +		_PR_LOCK(sproc_list_lock);
   1.656 +		PR_APPEND_LINK(&sparams.links, &sproc_list);
   1.657 +		rv = write(_pr_irix_primoridal_cpu_fd[1], &data, 1);
   1.658 +		PR_ASSERT(rv == 1);
   1.659 +		_PR_UNLOCK(sproc_list_lock);
   1.660 +		blockproc(getpid());
   1.661 +	}
   1.662 +}
   1.663 +
   1.664 +/*
   1.665 + * _PR_MD_WAKEUP_PRIMORDIAL_CPU
   1.666 + *
   1.667 + *		wakeup cpu 0
   1.668 + */
   1.669 +
   1.670 +void _PR_MD_WAKEUP_PRIMORDIAL_CPU()
   1.671 +{
   1.672 +char data = '0';
   1.673 +int rv;
   1.674 +
   1.675 +	rv = write(_pr_irix_primoridal_cpu_fd[1], &data, 1);
   1.676 +	PR_ASSERT(rv == 1);
   1.677 +}
   1.678 +
   1.679 +/*
   1.680 + * _PR_MD_primordial_cpu
   1.681 + *
   1.682 + *		process events that need to executed by the primordial cpu on each
   1.683 + *		iteration through the idle loop
   1.684 + */
   1.685 +
   1.686 +void _PR_MD_primordial_cpu()
   1.687 +{
   1.688 +PRCList *qp;
   1.689 +sproc_params *sp;
   1.690 +int pid;
   1.691 +
   1.692 +	_PR_LOCK(sproc_list_lock);
   1.693 +	while ((qp = sproc_list.next) != &sproc_list) {
   1.694 +		sp = SPROC_PARAMS_PTR(qp);
   1.695 +		PR_REMOVE_LINK(&sp->links);
   1.696 +		pid = sp->sd.creator_pid;
   1.697 +		(*(sp->sd.pid)) = sprocsp(sp->sd.entry,		/* startup func    */
   1.698 +							sp->sd.inh,            	/* attribute flags     */
   1.699 +							sp->sd.arg,     		/* thread param     */
   1.700 +							sp->sd.sp,             	/* stack address    */
   1.701 +							sp->sd.len);         	/* stack size     */
   1.702 +		unblockproc(pid);
   1.703 +	}
   1.704 +	_PR_UNLOCK(sproc_list_lock);
   1.705 +}
   1.706 +
   1.707 +PRStatus _MD_CreateThread(PRThread *thread, 
   1.708 +void (*start)(void *), 
   1.709 +PRThreadPriority priority, 
   1.710 +PRThreadScope scope, 
   1.711 +PRThreadState state, 
   1.712 +PRUint32 stackSize)
   1.713 +{
   1.714 +    typedef void (*SprocEntry) (void *, size_t);
   1.715 +    SprocEntry spentry = (SprocEntry)start;
   1.716 +    PRIntn is;
   1.717 +	PRThread *me = _PR_MD_CURRENT_THREAD();	
   1.718 +	PRInt32 pid;
   1.719 +	PRStatus rv;
   1.720 +
   1.721 +	if (!_PR_IS_NATIVE_THREAD(me))
   1.722 +		_PR_INTSOFF(is);
   1.723 +    thread->md.cvar_pollsem_select = 0;
   1.724 +    thread->flags |= _PR_GLOBAL_SCOPE;
   1.725 +
   1.726 +	thread->md.cvar_pollsemfd = -1;
   1.727 +	if (new_poll_sem(&thread->md,0) == PR_FAILURE) {
   1.728 +		if (!_PR_IS_NATIVE_THREAD(me))
   1.729 +			_PR_FAST_INTSON(is);
   1.730 +		return PR_FAILURE;
   1.731 +	}
   1.732 +	thread->md.cvar_pollsemfd =
   1.733 +		_PR_OPEN_POLL_SEM(thread->md.cvar_pollsem);
   1.734 +	if ((thread->md.cvar_pollsemfd < 0)) {
   1.735 +		free_poll_sem(&thread->md);
   1.736 +		if (!_PR_IS_NATIVE_THREAD(me))
   1.737 +			_PR_FAST_INTSON(is);
   1.738 +		return PR_FAILURE;
   1.739 +	}
   1.740 +
   1.741 +    create_sproc(spentry,            /* startup func    */
   1.742 +    			PR_SALL,            /* attribute flags     */
   1.743 +    			(void *)thread,     /* thread param     */
   1.744 +    			NULL,               /* stack address    */
   1.745 +    			stackSize, &pid);         /* stack size     */
   1.746 +    if (pid > 0) {
   1.747 +        _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs_created);
   1.748 +        _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs);
   1.749 +		rv = PR_SUCCESS;
   1.750 +		if (!_PR_IS_NATIVE_THREAD(me))
   1.751 +			_PR_FAST_INTSON(is);
   1.752 +        return rv;
   1.753 +    } else {
   1.754 +        close(thread->md.cvar_pollsemfd);
   1.755 +        thread->md.cvar_pollsemfd = -1;
   1.756 +		free_poll_sem(&thread->md);
   1.757 +        thread->md.cvar_pollsem = NULL;
   1.758 +        _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs_failed);
   1.759 +		if (!_PR_IS_NATIVE_THREAD(me))
   1.760 +			_PR_FAST_INTSON(is);
   1.761 +        return PR_FAILURE;
   1.762 +    }
   1.763 +}
   1.764 +
   1.765 +void _MD_CleanThread(PRThread *thread)
   1.766 +{
   1.767 +    if (thread->flags & _PR_GLOBAL_SCOPE) {
   1.768 +        close(thread->md.cvar_pollsemfd);
   1.769 +        thread->md.cvar_pollsemfd = -1;
   1.770 +		free_poll_sem(&thread->md);
   1.771 +        thread->md.cvar_pollsem = NULL;
   1.772 +    }
   1.773 +}
   1.774 +
   1.775 +void _MD_SetPriority(_MDThread *thread, PRThreadPriority newPri)
   1.776 +{
   1.777 +    return;
   1.778 +}
   1.779 +
   1.780 +extern void _MD_unix_terminate_waitpid_daemon(void);
   1.781 +
   1.782 +void
   1.783 +_MD_CleanupBeforeExit(void)
   1.784 +{
   1.785 +    extern PRInt32    _pr_cpus_exit;
   1.786 +
   1.787 +    _MD_unix_terminate_waitpid_daemon();
   1.788 +
   1.789 +	_pr_irix_exit_now = 1;
   1.790 +    if (_pr_numCPU > 1) {
   1.791 +        /*
   1.792 +         * Set a global flag, and wakeup all cpus which will notice the flag
   1.793 +         * and exit.
   1.794 +         */
   1.795 +        _pr_cpus_exit = getpid();
   1.796 +        _MD_Wakeup_CPUs();
   1.797 +        while(_pr_numCPU > 1) {
   1.798 +            _PR_WAIT_SEM(_pr_irix_exit_sem);
   1.799 +            _pr_numCPU--;
   1.800 +        }
   1.801 +    }
   1.802 +    /*
   1.803 +     * cause global threads on the recycle list to exit
   1.804 +     */
   1.805 +     _PR_DEADQ_LOCK;
   1.806 +     if (_PR_NUM_DEADNATIVE != 0) {
   1.807 +	PRThread *thread;
   1.808 +    	PRCList *ptr;
   1.809 +
   1.810 +        ptr = _PR_DEADNATIVEQ.next;
   1.811 +        while( ptr != &_PR_DEADNATIVEQ ) {
   1.812 +        	thread = _PR_THREAD_PTR(ptr);
   1.813 +		_MD_CVAR_POST_SEM(thread);
   1.814 +                ptr = ptr->next;
   1.815 +        } 
   1.816 +     }
   1.817 +     _PR_DEADQ_UNLOCK;
   1.818 +     while(_PR_NUM_DEADNATIVE > 1) {
   1.819 +	_PR_WAIT_SEM(_pr_irix_exit_sem);
   1.820 +	_PR_DEC_DEADNATIVE;
   1.821 +     }
   1.822 +}
   1.823 +
   1.824 +#ifdef _PR_HAVE_SGI_PRDA_PROCMASK
   1.825 +extern void __sgi_prda_procmask(int);
   1.826 +#endif
   1.827 +
   1.828 +PRStatus
   1.829 +_MD_InitAttachedThread(PRThread *thread, PRBool wakeup_parent)
   1.830 +{
   1.831 +	PRStatus rv = PR_SUCCESS;
   1.832 +
   1.833 +    if (thread->flags & _PR_GLOBAL_SCOPE) {
   1.834 +		if (new_poll_sem(&thread->md,0) == PR_FAILURE) {
   1.835 +			return PR_FAILURE;
   1.836 +		}
   1.837 +		thread->md.cvar_pollsemfd =
   1.838 +			_PR_OPEN_POLL_SEM(thread->md.cvar_pollsem);
   1.839 +		if ((thread->md.cvar_pollsemfd < 0)) {
   1.840 +			free_poll_sem(&thread->md);
   1.841 +			return PR_FAILURE;
   1.842 +		}
   1.843 +		if (_MD_InitThread(thread, PR_FALSE) == PR_FAILURE) {
   1.844 +			close(thread->md.cvar_pollsemfd);
   1.845 +			thread->md.cvar_pollsemfd = -1;
   1.846 +			free_poll_sem(&thread->md);
   1.847 +			thread->md.cvar_pollsem = NULL;
   1.848 +			return PR_FAILURE;
   1.849 +		}
   1.850 +    }
   1.851 +	return rv;
   1.852 +}
   1.853 +
   1.854 +PRStatus
   1.855 +_MD_InitThread(PRThread *thread, PRBool wakeup_parent)
   1.856 +{
   1.857 +    struct sigaction sigact;
   1.858 +	PRStatus rv = PR_SUCCESS;
   1.859 +
   1.860 +    if (thread->flags & _PR_GLOBAL_SCOPE) {
   1.861 +		thread->md.id = getpid();
   1.862 +        setblockproccnt(thread->md.id, 0);
   1.863 +		_MD_SET_SPROC_PID(getpid());	
   1.864 +#ifdef _PR_HAVE_SGI_PRDA_PROCMASK
   1.865 +		/*
   1.866 +		 * enable user-level processing of sigprocmask(); this is an
   1.867 +		 * undocumented feature available in Irix 6.2, 6.3, 6.4 and 6.5
   1.868 +		 */
   1.869 +		__sgi_prda_procmask(USER_LEVEL);
   1.870 +#endif
   1.871 +		/*
   1.872 +		 * set up SIGUSR1 handler; this is used to save state
   1.873 +		 */
   1.874 +		sigact.sa_handler = save_context_and_block;
   1.875 +		sigact.sa_flags = SA_RESTART;
   1.876 +		/*
   1.877 +		 * Must mask clock interrupts
   1.878 +		 */
   1.879 +		sigact.sa_mask = timer_set;
   1.880 +		sigaction(SIGUSR1, &sigact, 0);
   1.881 +
   1.882 +
   1.883 +		/*
   1.884 +		 * PR_SETABORTSIG is a new command implemented in a patch to
   1.885 +		 * Irix 6.2, 6.3 and 6.4. This causes a signal to be sent to all
   1.886 +		 * sprocs in the process when one of them terminates abnormally
   1.887 +		 *
   1.888 +		 */
   1.889 +		if (prctl(PR_SETABORTSIG, SIGKILL) < 0) {
   1.890 +			/*
   1.891 +			 *  if (errno == EINVAL)
   1.892 +			 *
   1.893 +			 *	PR_SETABORTSIG not supported under this OS.
   1.894 +			 *	You may want to get a recent kernel rollup patch that
   1.895 +			 *	supports this feature.
   1.896 +			 */
   1.897 +		}
   1.898 +		/*
   1.899 +		 * SIGCLD handler for detecting abormally-terminating
   1.900 +		 * sprocs and for reaping sprocs
   1.901 +		 */
   1.902 +		sigact.sa_handler = sigchld_handler;
   1.903 +		sigact.sa_flags = SA_RESTART;
   1.904 +		sigact.sa_mask = ints_off;
   1.905 +		sigaction(SIGCLD, &sigact, NULL);
   1.906 +    }
   1.907 +	return rv;
   1.908 +}
   1.909 +
   1.910 +/*
   1.911 + * PR_Cleanup should be executed on the primordial sproc; migrate the thread
   1.912 + * to the primordial cpu
   1.913 + */
   1.914 +
   1.915 +void _PR_MD_PRE_CLEANUP(PRThread *me)
   1.916 +{
   1.917 +PRIntn is;
   1.918 +_PRCPU *cpu = _pr_primordialCPU;
   1.919 +
   1.920 +	PR_ASSERT(cpu);
   1.921 +
   1.922 +	me->flags |= _PR_BOUND_THREAD;	
   1.923 +
   1.924 +	if (me->cpu->id != 0) {
   1.925 +		_PR_INTSOFF(is);
   1.926 +		_PR_RUNQ_LOCK(cpu);
   1.927 +		me->cpu = cpu;
   1.928 +		me->state = _PR_RUNNABLE;
   1.929 +		_PR_ADD_RUNQ(me, cpu, me->priority);
   1.930 +		_PR_RUNQ_UNLOCK(cpu);
   1.931 +		_MD_Wakeup_CPUs();
   1.932 +
   1.933 +		_PR_MD_SWITCH_CONTEXT(me);
   1.934 +
   1.935 +		_PR_FAST_INTSON(is);
   1.936 +		PR_ASSERT(me->cpu->id == 0);
   1.937 +	}
   1.938 +}
   1.939 +
   1.940 +/*
   1.941 + * process exiting
   1.942 + */
   1.943 +PR_EXTERN(void ) _MD_exit(PRIntn status)
   1.944 +{
   1.945 +PRThread *me = _PR_MD_CURRENT_THREAD();
   1.946 +
   1.947 +	/*
   1.948 +	 * the exit code of the process is the exit code of the primordial
   1.949 +	 * sproc
   1.950 +	 */
   1.951 +	if (!_PR_IS_NATIVE_THREAD(me) && (_PR_MD_CURRENT_CPU()->id == 0)) {
   1.952 +		/*
   1.953 +		 * primordial sproc case: call _exit directly
   1.954 +		 * Cause SIGKILL to be sent to other sprocs
   1.955 +		 */
   1.956 +		prctl(PR_SETEXITSIG, SIGKILL);
   1.957 +		_exit(status);
   1.958 +	} else {
   1.959 +		int rv;
   1.960 +		char data;
   1.961 +		sigset_t set;
   1.962 +
   1.963 +		/*
   1.964 +		 * non-primordial sproc case: cause the primordial sproc, cpu 0,
   1.965 +		 * to wakeup and call _exit
   1.966 +		 */
   1.967 +		_pr_irix_process_exit = 1;
   1.968 +		_pr_irix_process_exit_code = status;
   1.969 +		rv = write(_pr_irix_primoridal_cpu_fd[1], &data, 1);
   1.970 +		PR_ASSERT(rv == 1);
   1.971 +		/*
   1.972 +		 * block all signals and wait for SIGKILL to terminate this sproc
   1.973 +		 */
   1.974 +		sigfillset(&set);
   1.975 +		sigsuspend(&set);
   1.976 +		/*
   1.977 +		 * this code doesn't (shouldn't) execute
   1.978 +		 */
   1.979 +		prctl(PR_SETEXITSIG, SIGKILL);
   1.980 +		_exit(status);
   1.981 +	}
   1.982 +}
   1.983 +
   1.984 +/*
   1.985 + * Override the exit() function in libc to cause the process to exit
   1.986 + * when the primodial/main nspr thread calls exit. Calls to exit by any
   1.987 + * other thread simply result in a call to the exit function in libc.
   1.988 + * The exit code of the process is the exit code of the primordial
   1.989 + * sproc.
   1.990 + */
   1.991 +
   1.992 +void exit(int status)
   1.993 +{
   1.994 +PRThread *me, *thr;
   1.995 +PRCList *qp;
   1.996 +
   1.997 +	if (!_pr_initialized)  {
   1.998 +		if (!libc_exit) {
   1.999 +
  1.1000 +			if (!libc_handle)
  1.1001 +				libc_handle = dlopen("libc.so",RTLD_NOW);
  1.1002 +			if (libc_handle)
  1.1003 +				libc_exit = (void (*)(int)) dlsym(libc_handle, "exit");
  1.1004 +		}
  1.1005 +		if (libc_exit)
  1.1006 +			(*libc_exit)(status);
  1.1007 +		else
  1.1008 +			_exit(status);
  1.1009 +	}
  1.1010 +
  1.1011 +	me = _PR_MD_CURRENT_THREAD();
  1.1012 +
  1.1013 +	if (me == NULL) 		/* detached thread */
  1.1014 +		(*libc_exit)(status);
  1.1015 +
  1.1016 +	PR_ASSERT(_PR_IS_NATIVE_THREAD(me) ||
  1.1017 +						(_PR_MD_CURRENT_CPU())->id == me->cpu->id);
  1.1018 +
  1.1019 +	if (me->flags & _PR_PRIMORDIAL) {
  1.1020 +
  1.1021 +		me->flags |= _PR_BOUND_THREAD;	
  1.1022 +
  1.1023 +		PR_ASSERT((_PR_MD_CURRENT_CPU())->id == me->cpu->id);
  1.1024 +		if (me->cpu->id != 0) {
  1.1025 +			_PRCPU *cpu = _pr_primordialCPU;
  1.1026 +			PRIntn is;
  1.1027 +
  1.1028 +			_PR_INTSOFF(is);
  1.1029 +			_PR_RUNQ_LOCK(cpu);
  1.1030 +			me->cpu = cpu;
  1.1031 +			me->state = _PR_RUNNABLE;
  1.1032 +			_PR_ADD_RUNQ(me, cpu, me->priority);
  1.1033 +			_PR_RUNQ_UNLOCK(cpu);
  1.1034 +			_MD_Wakeup_CPUs();
  1.1035 +
  1.1036 +			_PR_MD_SWITCH_CONTEXT(me);
  1.1037 +
  1.1038 +			_PR_FAST_INTSON(is);
  1.1039 +		}
  1.1040 +
  1.1041 +		PR_ASSERT((_PR_MD_CURRENT_CPU())->id == 0);
  1.1042 +
  1.1043 +		if (prctl(PR_GETNSHARE) > 1) {
  1.1044 +#define SPROC_EXIT_WAIT_TIME 5
  1.1045 +			int sleep_cnt = SPROC_EXIT_WAIT_TIME;
  1.1046 +
  1.1047 +			/*
  1.1048 +			 * sprocs still running; caue cpus and recycled global threads
  1.1049 +			 * to exit
  1.1050 +			 */
  1.1051 +			_pr_irix_exit_now = 1;
  1.1052 +			if (_pr_numCPU > 1) {
  1.1053 +				_MD_Wakeup_CPUs();
  1.1054 +			}
  1.1055 +			 _PR_DEADQ_LOCK;
  1.1056 +			 if (_PR_NUM_DEADNATIVE != 0) {
  1.1057 +				PRThread *thread;
  1.1058 +				PRCList *ptr;
  1.1059 +
  1.1060 +				ptr = _PR_DEADNATIVEQ.next;
  1.1061 +				while( ptr != &_PR_DEADNATIVEQ ) {
  1.1062 +					thread = _PR_THREAD_PTR(ptr);
  1.1063 +					_MD_CVAR_POST_SEM(thread);
  1.1064 +					ptr = ptr->next;
  1.1065 +				} 
  1.1066 +			 }
  1.1067 +
  1.1068 +			while (sleep_cnt-- > 0) {
  1.1069 +				if (waitpid(0, NULL, WNOHANG) >= 0) 
  1.1070 +					sleep(1);
  1.1071 +				else
  1.1072 +					break;
  1.1073 +			}
  1.1074 +			prctl(PR_SETEXITSIG, SIGKILL);
  1.1075 +		}
  1.1076 +		(*libc_exit)(status);
  1.1077 +	} else {
  1.1078 +		/*
  1.1079 +		 * non-primordial thread; simply call exit in libc.
  1.1080 +		 */
  1.1081 +		(*libc_exit)(status);
  1.1082 +	}
  1.1083 +}
  1.1084 +
  1.1085 +
  1.1086 +void
  1.1087 +_MD_InitRunningCPU(_PRCPU *cpu)
  1.1088 +{
  1.1089 +    extern int _pr_md_pipefd[2];
  1.1090 +
  1.1091 +    _MD_unix_init_running_cpu(cpu);
  1.1092 +    cpu->md.id = getpid();
  1.1093 +	_MD_SET_SPROC_PID(getpid());	
  1.1094 +	if (_pr_md_pipefd[0] >= 0) {
  1.1095 +    	_PR_IOQ_MAX_OSFD(cpu) = _pr_md_pipefd[0];
  1.1096 +#ifndef _PR_USE_POLL
  1.1097 +    	FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(cpu));
  1.1098 +#endif
  1.1099 +	}
  1.1100 +}
  1.1101 +
  1.1102 +void
  1.1103 +_MD_ExitThread(PRThread *thread)
  1.1104 +{
  1.1105 +    if (thread->flags & _PR_GLOBAL_SCOPE) {
  1.1106 +        _MD_ATOMIC_DECREMENT(&_pr_md_irix_sprocs);
  1.1107 +        _MD_CLEAN_THREAD(thread);
  1.1108 +        _MD_SET_CURRENT_THREAD(NULL);
  1.1109 +    }
  1.1110 +}
  1.1111 +
  1.1112 +void
  1.1113 +_MD_SuspendCPU(_PRCPU *cpu)
  1.1114 +{
  1.1115 +    PRInt32 rv;
  1.1116 +
  1.1117 +	cpu->md.suspending_id = getpid();
  1.1118 +	rv = kill(cpu->md.id, SIGUSR1);
  1.1119 +	PR_ASSERT(rv == 0);
  1.1120 +	/*
  1.1121 +	 * now, block the current thread/cpu until woken up by the suspended
  1.1122 +	 * thread from it's SIGUSR1 signal handler
  1.1123 +	 */
  1.1124 +	blockproc(getpid());
  1.1125 +
  1.1126 +}
  1.1127 +
  1.1128 +void
  1.1129 +_MD_ResumeCPU(_PRCPU *cpu)
  1.1130 +{
  1.1131 +    unblockproc(cpu->md.id);
  1.1132 +}
  1.1133 +
  1.1134 +#if 0
  1.1135 +/*
  1.1136 + * save the register context of a suspended sproc
  1.1137 + */
  1.1138 +void get_context(PRThread *thr)
  1.1139 +{
  1.1140 +    int len, fd;
  1.1141 +    char pidstr[24];
  1.1142 +    char path[24];
  1.1143 +
  1.1144 +    /*
  1.1145 +     * open the file corresponding to this process in procfs
  1.1146 +     */
  1.1147 +    sprintf(path,"/proc/%s","00000");
  1.1148 +    len = strlen(path);
  1.1149 +    sprintf(pidstr,"%d",thr->md.id);
  1.1150 +    len -= strlen(pidstr);
  1.1151 +    sprintf(path + len,"%s",pidstr);
  1.1152 +    fd = open(path,O_RDONLY);
  1.1153 +    if (fd >= 0) {
  1.1154 +        (void) ioctl(fd, PIOCGREG, thr->md.gregs);
  1.1155 +        close(fd);
  1.1156 +    }
  1.1157 +    return;
  1.1158 +}
  1.1159 +#endif	/* 0 */
  1.1160 +
  1.1161 +void
  1.1162 +_MD_SuspendThread(PRThread *thread)
  1.1163 +{
  1.1164 +    PRInt32 rv;
  1.1165 +
  1.1166 +    PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) &&
  1.1167 +        _PR_IS_GCABLE_THREAD(thread));
  1.1168 +
  1.1169 +	thread->md.suspending_id = getpid();
  1.1170 +	rv = kill(thread->md.id, SIGUSR1);
  1.1171 +	PR_ASSERT(rv == 0);
  1.1172 +	/*
  1.1173 +	 * now, block the current thread/cpu until woken up by the suspended
  1.1174 +	 * thread from it's SIGUSR1 signal handler
  1.1175 +	 */
  1.1176 +	blockproc(getpid());
  1.1177 +}
  1.1178 +
  1.1179 +void
  1.1180 +_MD_ResumeThread(PRThread *thread)
  1.1181 +{
  1.1182 +    PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) &&
  1.1183 +        _PR_IS_GCABLE_THREAD(thread));
  1.1184 +    (void)unblockproc(thread->md.id);
  1.1185 +}
  1.1186 +
  1.1187 +/*
  1.1188 + * return the set of processors available for scheduling procs in the
  1.1189 + * "mask" argument
  1.1190 + */
  1.1191 +PRInt32 _MD_GetThreadAffinityMask(PRThread *unused, PRUint32 *mask)
  1.1192 +{
  1.1193 +    PRInt32 nprocs, rv;
  1.1194 +    struct pda_stat *pstat;
  1.1195 +#define MAX_PROCESSORS    32
  1.1196 +
  1.1197 +    nprocs = sysmp(MP_NPROCS);
  1.1198 +    if (nprocs < 0)
  1.1199 +        return(-1);
  1.1200 +    pstat = (struct pda_stat*)PR_MALLOC(sizeof(struct pda_stat) * nprocs);
  1.1201 +    if (pstat == NULL)
  1.1202 +        return(-1);
  1.1203 +    rv = sysmp(MP_STAT, pstat);
  1.1204 +    if (rv < 0) {
  1.1205 +        PR_DELETE(pstat);
  1.1206 +        return(-1);
  1.1207 +    }
  1.1208 +    /*
  1.1209 +     * look at the first 32 cpus
  1.1210 +     */
  1.1211 +    nprocs = (nprocs > MAX_PROCESSORS) ? MAX_PROCESSORS : nprocs;
  1.1212 +    *mask = 0;
  1.1213 +    while (nprocs) {
  1.1214 +        if ((pstat->p_flags & PDAF_ENABLED) &&
  1.1215 +            !(pstat->p_flags & PDAF_ISOLATED)) {
  1.1216 +            *mask |= (1 << pstat->p_cpuid);
  1.1217 +        }
  1.1218 +        nprocs--;
  1.1219 +        pstat++;
  1.1220 +    }
  1.1221 +    return 0;
  1.1222 +}
  1.1223 +
  1.1224 +static char *_thr_state[] = {
  1.1225 +    "UNBORN",
  1.1226 +    "RUNNABLE",
  1.1227 +    "RUNNING",
  1.1228 +    "LOCK_WAIT",
  1.1229 +    "COND_WAIT",
  1.1230 +    "JOIN_WAIT",
  1.1231 +    "IO_WAIT",
  1.1232 +    "SUSPENDED",
  1.1233 +    "DEAD"
  1.1234 +};
  1.1235 +
  1.1236 +void _PR_List_Threads()
  1.1237 +{
  1.1238 +    PRThread *thr;
  1.1239 +    void *handle;
  1.1240 +    struct _PRCPU *cpu;
  1.1241 +    PRCList *qp;
  1.1242 +    int len, fd;
  1.1243 +    char pidstr[24];
  1.1244 +    char path[24];
  1.1245 +    prpsinfo_t pinfo;
  1.1246 +
  1.1247 +
  1.1248 +    printf("\n%s %-s\n"," ","LOCAL Threads");
  1.1249 +    printf("%s %-s\n"," ","----- -------");
  1.1250 +    printf("%s %-14s %-10s %-12s %-3s %-10s %-10s %-12s\n\n"," ",
  1.1251 +        "Thread", "State", "Wait-Handle",
  1.1252 +        "Cpu","Stk-Base","Stk-Sz","SP");
  1.1253 +    for (qp = _PR_ACTIVE_LOCAL_THREADQ().next;
  1.1254 +        qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) {
  1.1255 +        thr = _PR_ACTIVE_THREAD_PTR(qp);
  1.1256 +        printf("%s 0x%-12x %-10s "," ",thr,_thr_state[thr->state]);
  1.1257 +        if (thr->state == _PR_LOCK_WAIT)
  1.1258 +            handle = thr->wait.lock;
  1.1259 +        else if (thr->state == _PR_COND_WAIT)
  1.1260 +            handle = thr->wait.cvar;
  1.1261 +        else
  1.1262 +            handle = NULL;
  1.1263 +        if (handle)
  1.1264 +            printf("0x%-10x ",handle);
  1.1265 +        else
  1.1266 +            printf("%-12s "," ");
  1.1267 +        printf("%-3d ",thr->cpu->id);
  1.1268 +        printf("0x%-8x ",thr->stack->stackBottom);
  1.1269 +        printf("0x%-8x ",thr->stack->stackSize);
  1.1270 +        printf("0x%-10x\n",thr->md.jb[JB_SP]);
  1.1271 +    }
  1.1272 +
  1.1273 +    printf("\n%s %-s\n"," ","GLOBAL Threads");
  1.1274 +    printf("%s %-s\n"," ","------ -------");
  1.1275 +    printf("%s %-14s %-6s %-12s %-12s %-12s %-12s\n\n"," ","Thread",
  1.1276 +        "Pid","State","Wait-Handle",
  1.1277 +        "Stk-Base","Stk-Sz");
  1.1278 +
  1.1279 +    for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next;
  1.1280 +        qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) {
  1.1281 +        thr = _PR_ACTIVE_THREAD_PTR(qp);
  1.1282 +        if (thr->cpu != NULL)
  1.1283 +            continue;        /* it is a cpu thread */
  1.1284 +        printf("%s 0x%-12x %-6d "," ",thr,thr->md.id);
  1.1285 +        /*
  1.1286 +         * check if the sproc is still running
  1.1287 +         * first call prctl(PR_GETSHMASK,pid) to check if
  1.1288 +         * the process is part of the share group (the pid
  1.1289 +         * could have been recycled by the OS)
  1.1290 +         */
  1.1291 +        if (prctl(PR_GETSHMASK,thr->md.id) < 0) {
  1.1292 +            printf("%-12s\n","TERMINATED");
  1.1293 +            continue;
  1.1294 +        }
  1.1295 +        /*
  1.1296 +         * Now, check if the sproc terminated and is in zombie
  1.1297 +         * state
  1.1298 +         */
  1.1299 +        sprintf(path,"/proc/pinfo/%s","00000");
  1.1300 +        len = strlen(path);
  1.1301 +        sprintf(pidstr,"%d",thr->md.id);
  1.1302 +        len -= strlen(pidstr);
  1.1303 +        sprintf(path + len,"%s",pidstr);
  1.1304 +        fd = open(path,O_RDONLY);
  1.1305 +        if (fd >= 0) {
  1.1306 +            if (ioctl(fd, PIOCPSINFO, &pinfo) < 0)
  1.1307 +                printf("%-12s ","TERMINATED");
  1.1308 +            else if (pinfo.pr_zomb)
  1.1309 +                printf("%-12s ","TERMINATED");
  1.1310 +            else
  1.1311 +                printf("%-12s ",_thr_state[thr->state]);
  1.1312 +            close(fd);
  1.1313 +        } else {
  1.1314 +            printf("%-12s ","TERMINATED");
  1.1315 +        }
  1.1316 +
  1.1317 +        if (thr->state == _PR_LOCK_WAIT)
  1.1318 +            handle = thr->wait.lock;
  1.1319 +        else if (thr->state == _PR_COND_WAIT)
  1.1320 +            handle = thr->wait.cvar;
  1.1321 +        else
  1.1322 +            handle = NULL;
  1.1323 +        if (handle)
  1.1324 +            printf("%-12x ",handle);
  1.1325 +        else
  1.1326 +            printf("%-12s "," ");
  1.1327 +        printf("0x%-10x ",thr->stack->stackBottom);
  1.1328 +        printf("0x%-10x\n",thr->stack->stackSize);
  1.1329 +    }
  1.1330 +
  1.1331 +    printf("\n%s %-s\n"," ","CPUs");
  1.1332 +    printf("%s %-s\n"," ","----");
  1.1333 +    printf("%s %-14s %-6s %-12s \n\n"," ","Id","Pid","State");
  1.1334 +
  1.1335 +
  1.1336 +    for (qp = _PR_CPUQ().next; qp != &_PR_CPUQ(); qp = qp->next) {
  1.1337 +        cpu = _PR_CPU_PTR(qp);
  1.1338 +        printf("%s %-14d %-6d "," ",cpu->id,cpu->md.id);
  1.1339 +        /*
  1.1340 +         * check if the sproc is still running
  1.1341 +         * first call prctl(PR_GETSHMASK,pid) to check if
  1.1342 +         * the process is part of the share group (the pid
  1.1343 +         * could have been recycled by the OS)
  1.1344 +         */
  1.1345 +        if (prctl(PR_GETSHMASK,cpu->md.id) < 0) {
  1.1346 +            printf("%-12s\n","TERMINATED");
  1.1347 +            continue;
  1.1348 +        }
  1.1349 +        /*
  1.1350 +         * Now, check if the sproc terminated and is in zombie
  1.1351 +         * state
  1.1352 +         */
  1.1353 +        sprintf(path,"/proc/pinfo/%s","00000");
  1.1354 +        len = strlen(path);
  1.1355 +        sprintf(pidstr,"%d",cpu->md.id);
  1.1356 +        len -= strlen(pidstr);
  1.1357 +        sprintf(path + len,"%s",pidstr);
  1.1358 +        fd = open(path,O_RDONLY);
  1.1359 +        if (fd >= 0) {
  1.1360 +            if (ioctl(fd, PIOCPSINFO, &pinfo) < 0)
  1.1361 +                printf("%-12s\n","TERMINATED");
  1.1362 +            else if (pinfo.pr_zomb)
  1.1363 +                printf("%-12s\n","TERMINATED");
  1.1364 +            else
  1.1365 +                printf("%-12s\n","RUNNING");
  1.1366 +            close(fd);
  1.1367 +        } else {
  1.1368 +            printf("%-12s\n","TERMINATED");
  1.1369 +        }
  1.1370 +
  1.1371 +    }
  1.1372 +    fflush(stdout);
  1.1373 +}
  1.1374 +#endif /* defined(_PR_PTHREADS) */ 
  1.1375 +
  1.1376 +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
  1.1377 +{
  1.1378 +#if !defined(_PR_PTHREADS)
  1.1379 +    if (isCurrent) {
  1.1380 +        (void) setjmp(t->md.jb);
  1.1381 +    }
  1.1382 +    *np = sizeof(t->md.jb) / sizeof(PRWord);
  1.1383 +    return (PRWord *) (t->md.jb);
  1.1384 +#else
  1.1385 +	*np = 0;
  1.1386 +	return NULL;
  1.1387 +#endif
  1.1388 +}
  1.1389 +
  1.1390 +void _MD_EarlyInit(void)
  1.1391 +{
  1.1392 +#if !defined(_PR_PTHREADS)
  1.1393 +    char *eval;
  1.1394 +    int fd;
  1.1395 +	extern int __ateachexit(void (*func)(void));
  1.1396 +
  1.1397 +    sigemptyset(&ints_off);
  1.1398 +    sigaddset(&ints_off, SIGALRM);
  1.1399 +    sigaddset(&ints_off, SIGIO);
  1.1400 +    sigaddset(&ints_off, SIGCLD);
  1.1401 +
  1.1402 +    if (eval = getenv("_NSPR_TERMINATE_ON_ERROR"))
  1.1403 +        _nspr_terminate_on_error = (0 == atoi(eval) == 0) ? PR_FALSE : PR_TRUE;
  1.1404 +
  1.1405 +    fd = open("/dev/zero",O_RDWR , 0);
  1.1406 +    if (fd < 0) {
  1.1407 +        perror("open /dev/zero failed");
  1.1408 +        exit(1);
  1.1409 +    }
  1.1410 +    /*
  1.1411 +     * Set up the sproc private data area.
  1.1412 +     * This region exists at the same address, _nspr_sproc_private, for
  1.1413 +     * every sproc, but each sproc gets a private copy of the region.
  1.1414 +     */
  1.1415 +    _nspr_sproc_private = (char*)mmap(0, _pr_pageSize, PROT_READ | PROT_WRITE,
  1.1416 +        MAP_PRIVATE| MAP_LOCAL, fd, 0);
  1.1417 +    if (_nspr_sproc_private == (void*)-1) {
  1.1418 +        perror("mmap /dev/zero failed");
  1.1419 +        exit(1);
  1.1420 +    }
  1.1421 +	_MD_SET_SPROC_PID(getpid());	
  1.1422 +    close(fd);
  1.1423 +	__ateachexit(irix_detach_sproc);
  1.1424 +#endif
  1.1425 +    _MD_IrixIntervalInit();
  1.1426 +}  /* _MD_EarlyInit */
  1.1427 +
  1.1428 +void _MD_IrixInit(void)
  1.1429 +{
  1.1430 +#if !defined(_PR_PTHREADS)
  1.1431 +    struct sigaction sigact;
  1.1432 +    PRThread *me = _PR_MD_CURRENT_THREAD();
  1.1433 +	int rv;
  1.1434 +
  1.1435 +#ifdef _PR_HAVE_SGI_PRDA_PROCMASK
  1.1436 +	/*
  1.1437 +	 * enable user-level processing of sigprocmask(); this is an undocumented
  1.1438 +	 * feature available in Irix 6.2, 6.3, 6.4 and 6.5
  1.1439 +	 */
  1.1440 +	__sgi_prda_procmask(USER_LEVEL);
  1.1441 +#endif
  1.1442 +
  1.1443 +	/*
  1.1444 +	 * set up SIGUSR1 handler; this is used to save state
  1.1445 +	 * during PR_SuspendAll
  1.1446 +	 */
  1.1447 +	sigact.sa_handler = save_context_and_block;
  1.1448 +	sigact.sa_flags = SA_RESTART;
  1.1449 +	sigact.sa_mask = ints_off;
  1.1450 +	sigaction(SIGUSR1, &sigact, 0);
  1.1451 +
  1.1452 +    /*
  1.1453 +     * Change the name of the core file from core to core.pid,
  1.1454 +     * This is inherited by the sprocs created by this process
  1.1455 +     */
  1.1456 +#ifdef PR_COREPID
  1.1457 +    prctl(PR_COREPID, 0, 1);
  1.1458 +#endif
  1.1459 +    /*
  1.1460 +     * Irix-specific terminate on error processing
  1.1461 +     */
  1.1462 +	/*
  1.1463 +	 * PR_SETABORTSIG is a new command implemented in a patch to
  1.1464 +	 * Irix 6.2, 6.3 and 6.4. This causes a signal to be sent to all
  1.1465 +	 * sprocs in the process when one of them terminates abnormally
  1.1466 +	 *
  1.1467 +	 */
  1.1468 +	if (prctl(PR_SETABORTSIG, SIGKILL) < 0) {
  1.1469 +		/*
  1.1470 +		 *  if (errno == EINVAL)
  1.1471 +		 *
  1.1472 +		 *	PR_SETABORTSIG not supported under this OS.
  1.1473 +		 *	You may want to get a recent kernel rollup patch that
  1.1474 +		 *	supports this feature.
  1.1475 +		 *
  1.1476 +		 */
  1.1477 +	}
  1.1478 +	/*
  1.1479 +	 * PR_SETEXITSIG -  send the SIGCLD signal to the parent
  1.1480 +	 *            sproc when any sproc terminates
  1.1481 +	 *
  1.1482 +	 *    This is used to cause the entire application to
  1.1483 +	 *    terminate when    any sproc terminates abnormally by
  1.1484 +	 *     receipt of a SIGSEGV, SIGBUS or SIGABRT signal.
  1.1485 +	 *    If this is not done, the application may seem
  1.1486 +	 *     "hung" to the user because the other sprocs may be
  1.1487 +	 *    waiting for resources held by the
  1.1488 +	 *    abnormally-terminating sproc.
  1.1489 +	 */
  1.1490 +	prctl(PR_SETEXITSIG, 0);
  1.1491 +
  1.1492 +	sigact.sa_handler = sigchld_handler;
  1.1493 +	sigact.sa_flags = SA_RESTART;
  1.1494 +	sigact.sa_mask = ints_off;
  1.1495 +	sigaction(SIGCLD, &sigact, NULL);
  1.1496 +
  1.1497 +    /*
  1.1498 +     * setup stack fields for the primordial thread
  1.1499 +     */
  1.1500 +    me->stack->stackSize = prctl(PR_GETSTACKSIZE);
  1.1501 +    me->stack->stackBottom = me->stack->stackTop - me->stack->stackSize;
  1.1502 +
  1.1503 +    rv = pipe(_pr_irix_primoridal_cpu_fd);
  1.1504 +    PR_ASSERT(rv == 0);
  1.1505 +#ifndef _PR_USE_POLL
  1.1506 +    _PR_IOQ_MAX_OSFD(me->cpu) = _pr_irix_primoridal_cpu_fd[0];
  1.1507 +    FD_SET(_pr_irix_primoridal_cpu_fd[0], &_PR_FD_READ_SET(me->cpu));
  1.1508 +#endif
  1.1509 +
  1.1510 +	libc_handle = dlopen("libc.so",RTLD_NOW);
  1.1511 +	PR_ASSERT(libc_handle != NULL);
  1.1512 +	libc_exit = (void (*)(int)) dlsym(libc_handle, "exit");
  1.1513 +	PR_ASSERT(libc_exit != NULL);
  1.1514 +	/* dlclose(libc_handle); */
  1.1515 +
  1.1516 +#endif /* _PR_PTHREADS */
  1.1517 +
  1.1518 +    _PR_UnixInit();
  1.1519 +}
  1.1520 +
  1.1521 +/**************************************************************************/
  1.1522 +/************** code and such for NSPR 2.0's interval times ***************/
  1.1523 +/**************************************************************************/
  1.1524 +
  1.1525 +#define PR_PSEC_PER_SEC 1000000000000ULL  /* 10^12 */
  1.1526 +
  1.1527 +#ifndef SGI_CYCLECNTR_SIZE
  1.1528 +#define SGI_CYCLECNTR_SIZE      165     /* Size user needs to use to read CC */
  1.1529 +#endif
  1.1530 +
  1.1531 +static PRIntn mmem_fd = -1;
  1.1532 +static PRIntn clock_width = 0;
  1.1533 +static void *iotimer_addr = NULL;
  1.1534 +static PRUint32 pr_clock_mask = 0;
  1.1535 +static PRUint32 pr_clock_shift = 0;
  1.1536 +static PRIntervalTime pr_ticks = 0;
  1.1537 +static PRUint32 pr_clock_granularity = 1;
  1.1538 +static PRUint32 pr_previous = 0, pr_residual = 0;
  1.1539 +static PRUint32 pr_ticks_per_second = 0;
  1.1540 +
  1.1541 +extern PRIntervalTime _PR_UNIX_GetInterval(void);
  1.1542 +extern PRIntervalTime _PR_UNIX_TicksPerSecond(void);
  1.1543 +
  1.1544 +static void _MD_IrixIntervalInit(void)
  1.1545 +{
  1.1546 +    /*
  1.1547 +     * As much as I would like, the service available through this
  1.1548 +     * interface on R3000's (aka, IP12) just isn't going to make it.
  1.1549 +     * The register is only 24 bits wide, and rolls over at a verocious
  1.1550 +     * rate.
  1.1551 +     */
  1.1552 +    PRUint32 one_tick = 0;
  1.1553 +    struct utsname utsinfo;
  1.1554 +    uname(&utsinfo);
  1.1555 +    if ((strncmp("IP12", utsinfo.machine, 4) != 0)
  1.1556 +        && ((mmem_fd = open("/dev/mmem", O_RDONLY)) != -1))
  1.1557 +    {
  1.1558 +        int poffmask = getpagesize() - 1;
  1.1559 +        __psunsigned_t phys_addr, raddr, cycleval;
  1.1560 +
  1.1561 +        phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval);
  1.1562 +        raddr = phys_addr & ~poffmask;
  1.1563 +        iotimer_addr = mmap(
  1.1564 +            0, poffmask, PROT_READ, MAP_PRIVATE, mmem_fd, (__psint_t)raddr);
  1.1565 +
  1.1566 +        clock_width = syssgi(SGI_CYCLECNTR_SIZE);
  1.1567 +        if (clock_width < 0)
  1.1568 +        {
  1.1569 +            /* 
  1.1570 +             * We must be executing on a 6.0 or earlier system, since the
  1.1571 +             * SGI_CYCLECNTR_SIZE call is not supported.
  1.1572 +             * 
  1.1573 +             * The only pre-6.1 platforms with 64-bit counters are
  1.1574 +             * IP19 and IP21 (Challenge, PowerChallenge, Onyx).
  1.1575 +             */
  1.1576 +            if (!strncmp(utsinfo.machine, "IP19", 4) ||
  1.1577 +                !strncmp(utsinfo.machine, "IP21", 4))
  1.1578 +                clock_width = 64;
  1.1579 +            else
  1.1580 +                clock_width = 32;
  1.1581 +        }
  1.1582 +
  1.1583 +        /*
  1.1584 +         * 'cycleval' is picoseconds / increment of the counter.
  1.1585 +         * I'm pushing for a tick to be 100 microseconds, 10^(-4).
  1.1586 +         * That leaves 10^(-8) left over, or 10^8 / cycleval.
  1.1587 +         * Did I do that right?
  1.1588 +         */
  1.1589 +
  1.1590 +        one_tick =  100000000UL / cycleval ;  /* 100 microseconds */
  1.1591 +
  1.1592 +        while (0 != one_tick)
  1.1593 +        {
  1.1594 +            pr_clock_shift += 1;
  1.1595 +            one_tick = one_tick >> 1;
  1.1596 +            pr_clock_granularity = pr_clock_granularity << 1;
  1.1597 +        }
  1.1598 +        pr_clock_mask = pr_clock_granularity - 1;  /* to make a mask out of it */
  1.1599 +        pr_ticks_per_second = PR_PSEC_PER_SEC
  1.1600 +                / ((PRUint64)pr_clock_granularity * (PRUint64)cycleval);
  1.1601 +            
  1.1602 +        iotimer_addr = (void*)
  1.1603 +            ((__psunsigned_t)iotimer_addr + (phys_addr & poffmask));
  1.1604 +    }
  1.1605 +    else
  1.1606 +    {
  1.1607 +        pr_ticks_per_second = _PR_UNIX_TicksPerSecond();
  1.1608 +    }
  1.1609 +}  /* _MD_IrixIntervalInit */
  1.1610 +
  1.1611 +PRIntervalTime _MD_IrixIntervalPerSec(void)
  1.1612 +{
  1.1613 +    return pr_ticks_per_second;
  1.1614 +}
  1.1615 +
  1.1616 +PRIntervalTime _MD_IrixGetInterval(void)
  1.1617 +{
  1.1618 +    if (mmem_fd != -1)
  1.1619 +    {
  1.1620 +        if (64 == clock_width)
  1.1621 +        {
  1.1622 +            PRUint64 temp = *(PRUint64*)iotimer_addr;
  1.1623 +            pr_ticks = (PRIntervalTime)(temp >> pr_clock_shift);
  1.1624 +        }
  1.1625 +        else
  1.1626 +        {
  1.1627 +            PRIntervalTime ticks = pr_ticks;
  1.1628 +            PRUint32 now = *(PRUint32*)iotimer_addr, temp;
  1.1629 +            PRUint32 residual = pr_residual, previous = pr_previous;
  1.1630 +
  1.1631 +            temp = now - previous + residual;
  1.1632 +            residual = temp & pr_clock_mask;
  1.1633 +            ticks += temp >> pr_clock_shift;
  1.1634 +
  1.1635 +            pr_previous = now;
  1.1636 +            pr_residual = residual;
  1.1637 +            pr_ticks = ticks;
  1.1638 +        }
  1.1639 +    }
  1.1640 +    else
  1.1641 +    {
  1.1642 +        /*
  1.1643 +         * No fast access. Use the time of day clock. This isn't the
  1.1644 +         * right answer since this clock can get set back, tick at odd
  1.1645 +         * rates, and it's expensive to acqurie.
  1.1646 +         */
  1.1647 +        pr_ticks = _PR_UNIX_GetInterval();
  1.1648 +    }
  1.1649 +    return pr_ticks;
  1.1650 +}  /* _MD_IrixGetInterval */
  1.1651 +

mercurial