Back to index

lightning-sunbird  0.9+nobinonly
irix.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "primpl.h"
00039 
00040 #include <signal.h>
00041 
00042 #include <sys/types.h>
00043 #include <fcntl.h>
00044 #include <unistd.h>
00045 #include <string.h>
00046 #include <sys/mman.h>
00047 #include <sys/syssgi.h>
00048 #include <sys/time.h>
00049 #include <sys/immu.h>
00050 #include <sys/utsname.h>
00051 #include <sys/sysmp.h>
00052 #include <sys/pda.h>
00053 #include <sys/prctl.h>
00054 #include <sys/wait.h>
00055 #include <sys/resource.h>
00056 #include <sys/procfs.h>
00057 #include <task.h>
00058 #include <dlfcn.h>
00059 
00060 static void _MD_IrixIntervalInit(void);
00061 
00062 #if defined(_PR_PTHREADS)
00063 /*
00064  * for compatibility with classic nspr
00065  */
00066 void _PR_IRIX_CHILD_PROCESS()
00067 {
00068 }
00069 #else  /* defined(_PR_PTHREADS) */
00070 
00071 static void irix_detach_sproc(void);
00072 char *_nspr_sproc_private;    /* ptr. to private region in every sproc */
00073 
00074 extern PRUintn    _pr_numCPU;
00075 
00076 typedef struct nspr_arena {
00077        PRCList links;
00078        usptr_t *usarena;
00079 } nspr_arena;
00080 
00081 #define ARENA_PTR(qp) \
00082        ((nspr_arena *) ((char*) (qp) - offsetof(nspr_arena , links)))
00083 
00084 static usptr_t *alloc_new_arena(void);
00085 
00086 PRCList arena_list = PR_INIT_STATIC_CLIST(&arena_list);
00087 ulock_t arena_list_lock;
00088 nspr_arena first_arena;
00089 int    _nspr_irix_arena_cnt = 1;
00090 
00091 PRCList sproc_list = PR_INIT_STATIC_CLIST(&sproc_list);
00092 ulock_t sproc_list_lock;
00093 
00094 typedef struct sproc_data {
00095        void (*entry) (void *, size_t);
00096        unsigned inh;
00097        void *arg;
00098        caddr_t sp;
00099        size_t len;
00100        int *pid;
00101        int creator_pid;
00102 } sproc_data;
00103 
00104 typedef struct sproc_params {
00105        PRCList links;
00106        sproc_data sd;
00107 } sproc_params;
00108 
00109 #define SPROC_PARAMS_PTR(qp) \
00110        ((sproc_params *) ((char*) (qp) - offsetof(sproc_params , links)))
00111 
00112 long   _nspr_irix_lock_cnt = 0;
00113 long   _nspr_irix_sem_cnt = 0;
00114 long   _nspr_irix_pollsem_cnt = 0;
00115 
00116 usptr_t *_pr_usArena;
00117 ulock_t _pr_heapLock;
00118 
00119 usema_t *_pr_irix_exit_sem;
00120 PRInt32 _pr_irix_exit_now = 0;
00121 PRInt32 _pr_irix_process_exit_code = 0;   /* exit code for PR_ProcessExit */
00122 PRInt32 _pr_irix_process_exit = 0; /* process exiting due to call to
00123                                                                          PR_ProcessExit */
00124 
00125 int _pr_irix_primoridal_cpu_fd[2] = { -1, -1 };
00126 static void (*libc_exit)(int) = NULL;
00127 static void *libc_handle = NULL;
00128 
00129 #define _NSPR_DEF_INITUSERS        100    /* default value of CONF_INITUSERS */
00130 #define _NSPR_DEF_INITSIZE         (4 * 1024 * 1024)    /* 4 MB */
00131 
00132 int _irix_initusers = _NSPR_DEF_INITUSERS;
00133 int _irix_initsize = _NSPR_DEF_INITSIZE;
00134 
00135 PRIntn _pr_io_in_progress, _pr_clock_in_progress;
00136 
00137 PRInt32 _pr_md_irix_sprocs_created, _pr_md_irix_sprocs_failed;
00138 PRInt32 _pr_md_irix_sprocs = 1;
00139 PRCList _pr_md_irix_sproc_list =
00140 PR_INIT_STATIC_CLIST(&_pr_md_irix_sproc_list);
00141 
00142 sigset_t ints_off;
00143 extern sigset_t timer_set;
00144 
00145 #if !defined(PR_SETABORTSIG)
00146 #define PR_SETABORTSIG 18
00147 #endif
00148 /*
00149  * terminate the entire application if any sproc exits abnormally
00150  */
00151 PRBool _nspr_terminate_on_error = PR_TRUE;
00152 
00153 /*
00154  * exported interface to set the shared arena parameters
00155  */
00156 void _PR_Irix_Set_Arena_Params(PRInt32 initusers, PRInt32 initsize)
00157 {
00158     _irix_initusers = initusers;
00159     _irix_initsize = initsize;
00160 }
00161 
00162 static usptr_t *alloc_new_arena()
00163 {
00164     return(usinit("/dev/zero"));
00165 }
00166 
00167 static PRStatus new_poll_sem(struct _MDThread *mdthr, int val)
00168 {
00169 PRIntn _is;
00170 PRStatus rv = PR_SUCCESS;
00171 usema_t *sem = NULL;
00172 PRCList *qp;
00173 nspr_arena *arena;
00174 usptr_t *irix_arena;
00175 PRThread *me = _MD_GET_ATTACHED_THREAD(); 
00176 
00177        if (me && !_PR_IS_NATIVE_THREAD(me))
00178               _PR_INTSOFF(_is); 
00179        _PR_LOCK(arena_list_lock);
00180        for (qp = arena_list.next; qp != &arena_list; qp = qp->next) {
00181               arena = ARENA_PTR(qp);
00182               sem = usnewpollsema(arena->usarena, val);
00183               if (sem != NULL) {
00184                      mdthr->cvar_pollsem = sem;
00185                      mdthr->pollsem_arena = arena->usarena;
00186                      break;
00187               }
00188        }
00189        if (sem == NULL) {
00190               /*
00191                * If no space left in the arena allocate a new one.
00192                */
00193               if (errno == ENOMEM) {
00194                      arena = PR_NEWZAP(nspr_arena);
00195                      if (arena != NULL) {
00196                             irix_arena = alloc_new_arena();
00197                             if (irix_arena) {
00198                                    PR_APPEND_LINK(&arena->links, &arena_list);
00199                                    _nspr_irix_arena_cnt++;
00200                                    arena->usarena = irix_arena;
00201                                    sem = usnewpollsema(arena->usarena, val);
00202                                    if (sem != NULL) {
00203                                           mdthr->cvar_pollsem = sem;
00204                                           mdthr->pollsem_arena = arena->usarena;
00205                                    } else
00206                                           rv = PR_FAILURE;
00207                             } else {
00208                                    PR_DELETE(arena);
00209                                    rv = PR_FAILURE;
00210                             }
00211 
00212                      } else
00213                             rv = PR_FAILURE;
00214               } else
00215                      rv = PR_FAILURE;
00216        }
00217        _PR_UNLOCK(arena_list_lock);
00218        if (me && !_PR_IS_NATIVE_THREAD(me))
00219               _PR_FAST_INTSON(_is);
00220        if (rv == PR_SUCCESS)
00221               _MD_ATOMIC_INCREMENT(&_nspr_irix_pollsem_cnt);
00222        return rv;
00223 }
00224 
00225 static void free_poll_sem(struct _MDThread *mdthr)
00226 {
00227 PRIntn _is;
00228 PRThread *me = _MD_GET_ATTACHED_THREAD(); 
00229 
00230        if (me && !_PR_IS_NATIVE_THREAD(me))
00231               _PR_INTSOFF(_is); 
00232        usfreepollsema(mdthr->cvar_pollsem, mdthr->pollsem_arena);
00233        if (me && !_PR_IS_NATIVE_THREAD(me))
00234               _PR_FAST_INTSON(_is);
00235        _MD_ATOMIC_DECREMENT(&_nspr_irix_pollsem_cnt);
00236 }
00237 
00238 static PRStatus new_lock(struct _MDLock *lockp)
00239 {
00240 PRIntn _is;
00241 PRStatus rv = PR_SUCCESS;
00242 ulock_t lock = NULL;
00243 PRCList *qp;
00244 nspr_arena *arena;
00245 usptr_t *irix_arena;
00246 PRThread *me = _MD_GET_ATTACHED_THREAD(); 
00247 
00248        if (me && !_PR_IS_NATIVE_THREAD(me))
00249               _PR_INTSOFF(_is); 
00250        _PR_LOCK(arena_list_lock);
00251        for (qp = arena_list.next; qp != &arena_list; qp = qp->next) {
00252               arena = ARENA_PTR(qp);
00253               lock = usnewlock(arena->usarena);
00254               if (lock != NULL) {
00255                      lockp->lock = lock;
00256                      lockp->arena = arena->usarena;
00257                      break;
00258               }
00259        }
00260        if (lock == NULL) {
00261               /*
00262                * If no space left in the arena allocate a new one.
00263                */
00264               if (errno == ENOMEM) {
00265                      arena = PR_NEWZAP(nspr_arena);
00266                      if (arena != NULL) {
00267                             irix_arena = alloc_new_arena();
00268                             if (irix_arena) {
00269                                    PR_APPEND_LINK(&arena->links, &arena_list);
00270                                    _nspr_irix_arena_cnt++;
00271                                    arena->usarena = irix_arena;
00272                                    lock = usnewlock(irix_arena);
00273                                    if (lock != NULL) {
00274                                           lockp->lock = lock;
00275                                           lockp->arena = arena->usarena;
00276                                    } else
00277                                           rv = PR_FAILURE;
00278                             } else {
00279                                    PR_DELETE(arena);
00280                                    rv = PR_FAILURE;
00281                             }
00282 
00283                      } else
00284                             rv = PR_FAILURE;
00285               } else
00286                      rv = PR_FAILURE;
00287        }
00288        _PR_UNLOCK(arena_list_lock);
00289        if (me && !_PR_IS_NATIVE_THREAD(me))
00290               _PR_FAST_INTSON(_is);
00291        if (rv == PR_SUCCESS)
00292               _MD_ATOMIC_INCREMENT(&_nspr_irix_lock_cnt);
00293        return rv;
00294 }
00295 
00296 static void free_lock(struct _MDLock *lockp)
00297 {
00298 PRIntn _is;
00299 PRThread *me = _MD_GET_ATTACHED_THREAD(); 
00300 
00301        if (me && !_PR_IS_NATIVE_THREAD(me))
00302               _PR_INTSOFF(_is); 
00303        usfreelock(lockp->lock, lockp->arena);
00304        if (me && !_PR_IS_NATIVE_THREAD(me))
00305               _PR_FAST_INTSON(_is);
00306        _MD_ATOMIC_DECREMENT(&_nspr_irix_lock_cnt);
00307 }
00308 
00309 void _MD_FREE_LOCK(struct _MDLock *lockp)
00310 {
00311        PRIntn _is;
00312        PRThread *me = _MD_GET_ATTACHED_THREAD(); 
00313 
00314        if (me && !_PR_IS_NATIVE_THREAD(me))
00315               _PR_INTSOFF(_is); 
00316        free_lock(lockp);
00317        if (me && !_PR_IS_NATIVE_THREAD(me))
00318               _PR_FAST_INTSON(_is);
00319 }
00320 
00321 /*
00322  * _MD_get_attached_thread
00323  *            Return the thread pointer of the current thread if it is attached.
00324  *
00325  *            This function is needed for Irix because the thread-local-storage is
00326  *            implemented by mmapin'g a page with the MAP_LOCAL flag. This causes the
00327  *            sproc-private page to inherit contents of the page of the caller of sproc().
00328  */
00329 PRThread *_MD_get_attached_thread(void)
00330 {
00331 
00332        if (_MD_GET_SPROC_PID() == get_pid())
00333               return _MD_THIS_THREAD();
00334        else
00335               return 0;
00336 }
00337 
00338 /*
00339  * _MD_get_current_thread
00340  *            Return the thread pointer of the current thread (attaching it if
00341  *            necessary)
00342  */
00343 PRThread *_MD_get_current_thread(void)
00344 {
00345 PRThread *me;
00346 
00347        me = _MD_GET_ATTACHED_THREAD();
00348     if (NULL == me) {
00349         me = _PRI_AttachThread(
00350             PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0);
00351     }
00352     PR_ASSERT(me != NULL);
00353        return(me);
00354 }
00355 
00356 /*
00357  * irix_detach_sproc
00358  *            auto-detach a sproc when it exits
00359  */
00360 void irix_detach_sproc(void)
00361 {
00362 PRThread *me;
00363 
00364        me = _MD_GET_ATTACHED_THREAD();
00365        if ((me != NULL) && (me->flags & _PR_ATTACHED)) {
00366               _PRI_DetachThread();
00367        }
00368 }
00369 
00370 
00371 PRStatus _MD_NEW_LOCK(struct _MDLock *lockp)
00372 {
00373     PRStatus rv;
00374     PRIntn is;
00375     PRThread *me = _MD_GET_ATTACHED_THREAD();    
00376 
00377        if (me && !_PR_IS_NATIVE_THREAD(me))
00378               _PR_INTSOFF(is);
00379        rv = new_lock(lockp);
00380        if (me && !_PR_IS_NATIVE_THREAD(me))
00381               _PR_FAST_INTSON(is);
00382        return rv;
00383 }
00384 
00385 static void
00386 sigchld_handler(int sig)
00387 {
00388     pid_t pid;
00389     int status;
00390 
00391     /*
00392      * If an sproc exited abnormally send a SIGKILL signal to all the
00393      * sprocs in the process to terminate the application
00394      */
00395     while ((pid = waitpid(0, &status, WNOHANG)) > 0) {
00396         if (WIFSIGNALED(status) && ((WTERMSIG(status) == SIGSEGV) ||
00397             (WTERMSIG(status) == SIGBUS) ||
00398             (WTERMSIG(status) == SIGABRT) ||
00399             (WTERMSIG(status) == SIGILL))) {
00400 
00401                             prctl(PR_SETEXITSIG, SIGKILL);
00402                             _exit(status);
00403                      }
00404     }
00405 }
00406 
00407 static void save_context_and_block(int sig)
00408 {
00409 PRThread *me = _PR_MD_CURRENT_THREAD();
00410 _PRCPU *cpu = _PR_MD_CURRENT_CPU();
00411 
00412        /*
00413         * save context
00414         */
00415        (void) setjmp(me->md.jb);
00416        /*
00417         * unblock the suspending thread
00418         */
00419        if (me->cpu) {
00420               /*
00421                * I am a cpu thread, not a user-created GLOBAL thread
00422                */
00423               unblockproc(cpu->md.suspending_id);       
00424        } else {
00425               unblockproc(me->md.suspending_id); 
00426        }
00427        /*
00428         * now, block current thread
00429         */
00430        blockproc(getpid());
00431 }
00432 
00433 /*
00434 ** The irix kernel has a bug in it which causes async connect's which are
00435 ** interrupted by a signal to fail terribly (EADDRINUSE is returned). 
00436 ** We work around the bug by blocking signals during the async connect
00437 ** attempt.
00438 */
00439 PRInt32 _MD_irix_connect(
00440     PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen, PRIntervalTime timeout)
00441 {
00442     PRInt32 rv;
00443     sigset_t oldset;
00444 
00445     sigprocmask(SIG_BLOCK, &ints_off, &oldset);
00446     rv = connect(osfd, addr, addrlen);
00447     sigprocmask(SIG_SETMASK, &oldset, 0);
00448 
00449     return(rv);
00450 }
00451 
00452 #include "prprf.h"
00453 
00454 /********************************************************************/
00455 /********************************************************************/
00456 /*************** Various thread like things for IRIX ****************/
00457 /********************************************************************/
00458 /********************************************************************/
00459 
00460 void *_MD_GetSP(PRThread *t)
00461 {
00462     PRThread *me = _PR_MD_CURRENT_THREAD();
00463     void *sp;
00464 
00465     if (me == t)
00466         (void) setjmp(t->md.jb);
00467 
00468     sp = (void *)(t->md.jb[JB_SP]);
00469     PR_ASSERT((sp >= (void *) t->stack->stackBottom) &&
00470         (sp <= (void *) (t->stack->stackBottom + t->stack->stackSize)));
00471     return(sp);
00472 }
00473 
00474 void _MD_InitLocks()
00475 {
00476     char buf[200];
00477     char *init_users, *init_size;
00478 
00479     PR_snprintf(buf, sizeof(buf), "/dev/zero");
00480 
00481     if (init_users = getenv("_NSPR_IRIX_INITUSERS"))
00482         _irix_initusers = atoi(init_users);
00483 
00484     if (init_size = getenv("_NSPR_IRIX_INITSIZE"))
00485         _irix_initsize = atoi(init_size);
00486 
00487     usconfig(CONF_INITUSERS, _irix_initusers);
00488     usconfig(CONF_INITSIZE, _irix_initsize);
00489     usconfig(CONF_AUTOGROW, 1);
00490     usconfig(CONF_AUTORESV, 1);
00491        if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0) {
00492               perror("PR_Init: unable to config mutex arena");
00493               exit(-1);
00494        }
00495 
00496     _pr_usArena = usinit(buf);
00497     if (!_pr_usArena) {
00498         fprintf(stderr,
00499             "PR_Init: Error - unable to create lock/monitor arena\n");
00500         exit(-1);
00501     }
00502     _pr_heapLock = usnewlock(_pr_usArena);
00503        _nspr_irix_lock_cnt++;
00504 
00505     arena_list_lock = usnewlock(_pr_usArena);
00506        _nspr_irix_lock_cnt++;
00507 
00508     sproc_list_lock = usnewlock(_pr_usArena);
00509        _nspr_irix_lock_cnt++;
00510 
00511        _pr_irix_exit_sem = usnewsema(_pr_usArena, 0);
00512        _nspr_irix_sem_cnt = 1;
00513 
00514        first_arena.usarena = _pr_usArena;
00515        PR_INIT_CLIST(&first_arena.links);
00516        PR_APPEND_LINK(&first_arena.links, &arena_list);
00517 }
00518 
00519 /* _PR_IRIX_CHILD_PROCESS is a private API for Server group */
00520 void _PR_IRIX_CHILD_PROCESS()
00521 {
00522 extern PRUint32 _pr_global_threads;
00523 
00524     PR_ASSERT(_PR_MD_CURRENT_CPU() == _pr_primordialCPU);
00525     PR_ASSERT(_pr_numCPU == 1);
00526     PR_ASSERT(_pr_global_threads == 0);
00527     /*
00528      * save the new pid
00529      */
00530     _pr_primordialCPU->md.id = getpid();
00531        _MD_SET_SPROC_PID(getpid());       
00532 }
00533 
00534 static PRStatus pr_cvar_wait_sem(PRThread *thread, PRIntervalTime timeout)
00535 {
00536     int rv;
00537 
00538 #ifdef _PR_USE_POLL
00539        struct pollfd pfd;
00540        int msecs;
00541 
00542        if (timeout == PR_INTERVAL_NO_TIMEOUT)
00543               msecs = -1;
00544        else
00545               msecs  = PR_IntervalToMilliseconds(timeout);
00546 #else
00547     struct timeval tv, *tvp;
00548     fd_set rd;
00549 
00550        if(timeout == PR_INTERVAL_NO_TIMEOUT)
00551               tvp = NULL;
00552        else {
00553               tv.tv_sec = PR_IntervalToSeconds(timeout);
00554               tv.tv_usec = PR_IntervalToMicroseconds(
00555               timeout - PR_SecondsToInterval(tv.tv_sec));
00556               tvp = &tv;
00557        }
00558        FD_ZERO(&rd);
00559        FD_SET(thread->md.cvar_pollsemfd, &rd);
00560 #endif
00561 
00562     /*
00563      * call uspsema only if a previous select call on this semaphore
00564      * did not timeout
00565      */
00566     if (!thread->md.cvar_pollsem_select) {
00567         rv = _PR_WAIT_SEM(thread->md.cvar_pollsem);
00568               PR_ASSERT(rv >= 0);
00569        } else
00570         rv = 0;
00571 again:
00572     if(!rv) {
00573 #ifdef _PR_USE_POLL
00574               pfd.events = POLLIN;
00575               pfd.fd = thread->md.cvar_pollsemfd;
00576               rv = _MD_POLL(&pfd, 1, msecs);
00577 #else
00578               rv = _MD_SELECT(thread->md.cvar_pollsemfd + 1, &rd, NULL,NULL,tvp);
00579 #endif
00580         if ((rv == -1) && (errno == EINTR)) {
00581                      rv = 0;
00582                      goto again;
00583               }
00584               PR_ASSERT(rv >= 0);
00585        }
00586 
00587     if (rv > 0) {
00588         /*
00589          * acquired the semaphore, call uspsema next time
00590          */
00591         thread->md.cvar_pollsem_select = 0;
00592         return PR_SUCCESS;
00593     } else {
00594         /*
00595          * select timed out; must call select, not uspsema, when trying
00596          * to acquire the semaphore the next time
00597          */
00598         thread->md.cvar_pollsem_select = 1;
00599         return PR_FAILURE;
00600     }
00601 }
00602 
00603 PRStatus _MD_wait(PRThread *thread, PRIntervalTime ticks)
00604 {
00605     if ( thread->flags & _PR_GLOBAL_SCOPE ) {
00606        _MD_CHECK_FOR_EXIT();
00607         if (pr_cvar_wait_sem(thread, ticks) == PR_FAILURE) {
00608            _MD_CHECK_FOR_EXIT();
00609             /*
00610              * wait timed out
00611              */
00612             _PR_THREAD_LOCK(thread);
00613             if (thread->wait.cvar) {
00614                 /*
00615                  * The thread will remove itself from the waitQ
00616                  * of the cvar in _PR_WaitCondVar
00617                  */
00618                 thread->wait.cvar = NULL;
00619                 thread->state =  _PR_RUNNING;
00620                 _PR_THREAD_UNLOCK(thread);
00621             }  else {
00622                 _PR_THREAD_UNLOCK(thread);
00623                 /*
00624              * This thread was woken up by a notifying thread
00625              * at the same time as a timeout; so, consume the
00626              * extra post operation on the semaphore
00627              */
00628                _MD_CHECK_FOR_EXIT();
00629             pr_cvar_wait_sem(thread, PR_INTERVAL_NO_TIMEOUT);
00630             }
00631            _MD_CHECK_FOR_EXIT();
00632         }
00633     } else {
00634         _PR_MD_SWITCH_CONTEXT(thread);
00635     }
00636     return PR_SUCCESS;
00637 }
00638 
00639 PRStatus _MD_WakeupWaiter(PRThread *thread)
00640 {
00641     PRThread *me = _PR_MD_CURRENT_THREAD();
00642     PRIntn is;
00643 
00644        PR_ASSERT(_pr_md_idle_cpus >= 0);
00645     if (thread == NULL) {
00646               if (_pr_md_idle_cpus)
00647               _MD_Wakeup_CPUs();
00648     } else if (!_PR_IS_NATIVE_THREAD(thread)) {
00649               if (_pr_md_idle_cpus)
00650                      _MD_Wakeup_CPUs();
00651     } else {
00652               PR_ASSERT(_PR_IS_NATIVE_THREAD(thread));
00653               if (!_PR_IS_NATIVE_THREAD(me))
00654                      _PR_INTSOFF(is);
00655               _MD_CVAR_POST_SEM(thread);
00656               if (!_PR_IS_NATIVE_THREAD(me))
00657                      _PR_FAST_INTSON(is);
00658     } 
00659     return PR_SUCCESS;
00660 }
00661 
00662 void create_sproc (void (*entry) (void *, size_t), unsigned inh,
00663                                    void *arg, caddr_t sp, size_t len, int *pid)
00664 {
00665 sproc_params sparams;
00666 char data;
00667 int rv;
00668 PRThread *me = _PR_MD_CURRENT_THREAD();
00669 
00670        if (!_PR_IS_NATIVE_THREAD(me) && (_PR_MD_CURRENT_CPU()->id == 0)) {
00671               *pid = sprocsp(entry,              /* startup func             */
00672                                           inh,        /* attribute flags     */
00673                                           arg,          /* thread param             */
00674                                           sp,         /* stack address       */
00675                                           len);       /* stack size          */
00676        } else {
00677               sparams.sd.entry = entry;
00678               sparams.sd.inh = inh;
00679               sparams.sd.arg = arg;
00680               sparams.sd.sp = sp;
00681               sparams.sd.len = len;
00682               sparams.sd.pid = pid;
00683               sparams.sd.creator_pid = getpid();
00684               _PR_LOCK(sproc_list_lock);
00685               PR_APPEND_LINK(&sparams.links, &sproc_list);
00686               rv = write(_pr_irix_primoridal_cpu_fd[1], &data, 1);
00687               PR_ASSERT(rv == 1);
00688               _PR_UNLOCK(sproc_list_lock);
00689               blockproc(getpid());
00690        }
00691 }
00692 
00693 /*
00694  * _PR_MD_WAKEUP_PRIMORDIAL_CPU
00695  *
00696  *            wakeup cpu 0
00697  */
00698 
00699 void _PR_MD_WAKEUP_PRIMORDIAL_CPU()
00700 {
00701 char data = '0';
00702 int rv;
00703 
00704        rv = write(_pr_irix_primoridal_cpu_fd[1], &data, 1);
00705        PR_ASSERT(rv == 1);
00706 }
00707 
00708 /*
00709  * _PR_MD_primordial_cpu
00710  *
00711  *            process events that need to executed by the primordial cpu on each
00712  *            iteration through the idle loop
00713  */
00714 
00715 void _PR_MD_primordial_cpu()
00716 {
00717 PRCList *qp;
00718 sproc_params *sp;
00719 int pid;
00720 
00721        _PR_LOCK(sproc_list_lock);
00722        while ((qp = sproc_list.next) != &sproc_list) {
00723               sp = SPROC_PARAMS_PTR(qp);
00724               PR_REMOVE_LINK(&sp->links);
00725               pid = sp->sd.creator_pid;
00726               (*(sp->sd.pid)) = sprocsp(sp->sd.entry,          /* startup func    */
00727                                                  sp->sd.inh,                 /* attribute flags     */
00728                                                  sp->sd.arg,                 /* thread param     */
00729                                                  sp->sd.sp,                  /* stack address    */
00730                                                  sp->sd.len);                /* stack size     */
00731               unblockproc(pid);
00732        }
00733        _PR_UNLOCK(sproc_list_lock);
00734 }
00735 
00736 PRStatus _MD_CreateThread(PRThread *thread, 
00737 void (*start)(void *), 
00738 PRThreadPriority priority, 
00739 PRThreadScope scope, 
00740 PRThreadState state, 
00741 PRUint32 stackSize)
00742 {
00743     typedef void (*SprocEntry) (void *, size_t);
00744     SprocEntry spentry = (SprocEntry)start;
00745     PRIntn is;
00746        PRThread *me = _PR_MD_CURRENT_THREAD();   
00747        PRInt32 pid;
00748        PRStatus rv;
00749 
00750        if (!_PR_IS_NATIVE_THREAD(me))
00751               _PR_INTSOFF(is);
00752     thread->md.cvar_pollsem_select = 0;
00753     thread->flags |= _PR_GLOBAL_SCOPE;
00754 
00755        thread->md.cvar_pollsemfd = -1;
00756        if (new_poll_sem(&thread->md,0) == PR_FAILURE) {
00757               if (!_PR_IS_NATIVE_THREAD(me))
00758                      _PR_FAST_INTSON(is);
00759               return PR_FAILURE;
00760        }
00761        thread->md.cvar_pollsemfd =
00762               _PR_OPEN_POLL_SEM(thread->md.cvar_pollsem);
00763        if ((thread->md.cvar_pollsemfd < 0)) {
00764               free_poll_sem(&thread->md);
00765               if (!_PR_IS_NATIVE_THREAD(me))
00766                      _PR_FAST_INTSON(is);
00767               return PR_FAILURE;
00768        }
00769 
00770     create_sproc(spentry,            /* startup func    */
00771                      PR_SALL,            /* attribute flags     */
00772                      (void *)thread,     /* thread param     */
00773                      NULL,               /* stack address    */
00774                      stackSize, &pid);         /* stack size     */
00775     if (pid > 0) {
00776         _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs_created);
00777         _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs);
00778               rv = PR_SUCCESS;
00779               if (!_PR_IS_NATIVE_THREAD(me))
00780                      _PR_FAST_INTSON(is);
00781         return rv;
00782     } else {
00783         close(thread->md.cvar_pollsemfd);
00784         thread->md.cvar_pollsemfd = -1;
00785               free_poll_sem(&thread->md);
00786         thread->md.cvar_pollsem = NULL;
00787         _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs_failed);
00788               if (!_PR_IS_NATIVE_THREAD(me))
00789                      _PR_FAST_INTSON(is);
00790         return PR_FAILURE;
00791     }
00792 }
00793 
00794 void _MD_CleanThread(PRThread *thread)
00795 {
00796     if (thread->flags & _PR_GLOBAL_SCOPE) {
00797         close(thread->md.cvar_pollsemfd);
00798         thread->md.cvar_pollsemfd = -1;
00799               free_poll_sem(&thread->md);
00800         thread->md.cvar_pollsem = NULL;
00801     }
00802 }
00803 
00804 void _MD_SetPriority(_MDThread *thread, PRThreadPriority newPri)
00805 {
00806     return;
00807 }
00808 
00809 extern void _MD_unix_terminate_waitpid_daemon(void);
00810 
00811 void
00812 _MD_CleanupBeforeExit(void)
00813 {
00814     extern PRInt32    _pr_cpus_exit;
00815 
00816     _MD_unix_terminate_waitpid_daemon();
00817 
00818        _pr_irix_exit_now = 1;
00819     if (_pr_numCPU > 1) {
00820         /*
00821          * Set a global flag, and wakeup all cpus which will notice the flag
00822          * and exit.
00823          */
00824         _pr_cpus_exit = getpid();
00825         _MD_Wakeup_CPUs();
00826         while(_pr_numCPU > 1) {
00827             _PR_WAIT_SEM(_pr_irix_exit_sem);
00828             _pr_numCPU--;
00829         }
00830     }
00831     /*
00832      * cause global threads on the recycle list to exit
00833      */
00834      _PR_DEADQ_LOCK;
00835      if (_PR_NUM_DEADNATIVE != 0) {
00836        PRThread *thread;
00837        PRCList *ptr;
00838 
00839         ptr = _PR_DEADNATIVEQ.next;
00840         while( ptr != &_PR_DEADNATIVEQ ) {
00841               thread = _PR_THREAD_PTR(ptr);
00842               _MD_CVAR_POST_SEM(thread);
00843                 ptr = ptr->next;
00844         } 
00845      }
00846      _PR_DEADQ_UNLOCK;
00847      while(_PR_NUM_DEADNATIVE > 1) {
00848        _PR_WAIT_SEM(_pr_irix_exit_sem);
00849        _PR_DEC_DEADNATIVE;
00850      }
00851 }
00852 
00853 #ifdef _PR_HAVE_SGI_PRDA_PROCMASK
00854 extern void __sgi_prda_procmask(int);
00855 #endif
00856 
00857 PRStatus
00858 _MD_InitAttachedThread(PRThread *thread, PRBool wakeup_parent)
00859 {
00860        PRStatus rv = PR_SUCCESS;
00861 
00862     if (thread->flags & _PR_GLOBAL_SCOPE) {
00863               if (new_poll_sem(&thread->md,0) == PR_FAILURE) {
00864                      return PR_FAILURE;
00865               }
00866               thread->md.cvar_pollsemfd =
00867                      _PR_OPEN_POLL_SEM(thread->md.cvar_pollsem);
00868               if ((thread->md.cvar_pollsemfd < 0)) {
00869                      free_poll_sem(&thread->md);
00870                      return PR_FAILURE;
00871               }
00872               if (_MD_InitThread(thread, PR_FALSE) == PR_FAILURE) {
00873                      close(thread->md.cvar_pollsemfd);
00874                      thread->md.cvar_pollsemfd = -1;
00875                      free_poll_sem(&thread->md);
00876                      thread->md.cvar_pollsem = NULL;
00877                      return PR_FAILURE;
00878               }
00879     }
00880        return rv;
00881 }
00882 
00883 PRStatus
00884 _MD_InitThread(PRThread *thread, PRBool wakeup_parent)
00885 {
00886     struct sigaction sigact;
00887        PRStatus rv = PR_SUCCESS;
00888 
00889     if (thread->flags & _PR_GLOBAL_SCOPE) {
00890               thread->md.id = getpid();
00891         setblockproccnt(thread->md.id, 0);
00892               _MD_SET_SPROC_PID(getpid());       
00893 #ifdef _PR_HAVE_SGI_PRDA_PROCMASK
00894               /*
00895                * enable user-level processing of sigprocmask(); this is an
00896                * undocumented feature available in Irix 6.2, 6.3, 6.4 and 6.5
00897                */
00898               __sgi_prda_procmask(USER_LEVEL);
00899 #endif
00900               /*
00901                * set up SIGUSR1 handler; this is used to save state
00902                */
00903               sigact.sa_handler = save_context_and_block;
00904               sigact.sa_flags = SA_RESTART;
00905               /*
00906                * Must mask clock interrupts
00907                */
00908               sigact.sa_mask = timer_set;
00909               sigaction(SIGUSR1, &sigact, 0);
00910 
00911 
00912               /*
00913                * PR_SETABORTSIG is a new command implemented in a patch to
00914                * Irix 6.2, 6.3 and 6.4. This causes a signal to be sent to all
00915                * sprocs in the process when one of them terminates abnormally
00916                *
00917                */
00918               if (prctl(PR_SETABORTSIG, SIGKILL) < 0) {
00919                      /*
00920                       *  if (errno == EINVAL)
00921                       *
00922                       *     PR_SETABORTSIG not supported under this OS.
00923                       *     You may want to get a recent kernel rollup patch that
00924                       *     supports this feature.
00925                       */
00926               }
00927               /*
00928                * SIGCLD handler for detecting abormally-terminating
00929                * sprocs and for reaping sprocs
00930                */
00931               sigact.sa_handler = sigchld_handler;
00932               sigact.sa_flags = SA_RESTART;
00933               sigact.sa_mask = ints_off;
00934               sigaction(SIGCLD, &sigact, NULL);
00935     }
00936        return rv;
00937 }
00938 
00939 /*
00940  * PR_Cleanup should be executed on the primordial sproc; migrate the thread
00941  * to the primordial cpu
00942  */
00943 
00944 void _PR_MD_PRE_CLEANUP(PRThread *me)
00945 {
00946 PRIntn is;
00947 _PRCPU *cpu = _pr_primordialCPU;
00948 
00949        PR_ASSERT(cpu);
00950 
00951        me->flags |= _PR_BOUND_THREAD;     
00952 
00953        if (me->cpu->id != 0) {
00954               _PR_INTSOFF(is);
00955               _PR_RUNQ_LOCK(cpu);
00956               me->cpu = cpu;
00957               me->state = _PR_RUNNABLE;
00958               _PR_ADD_RUNQ(me, cpu, me->priority);
00959               _PR_RUNQ_UNLOCK(cpu);
00960               _MD_Wakeup_CPUs();
00961 
00962               _PR_MD_SWITCH_CONTEXT(me);
00963 
00964               _PR_FAST_INTSON(is);
00965               PR_ASSERT(me->cpu->id == 0);
00966        }
00967 }
00968 
00969 /*
00970  * process exiting
00971  */
00972 PR_EXTERN(void ) _MD_exit(PRIntn status)
00973 {
00974 PRThread *me = _PR_MD_CURRENT_THREAD();
00975 
00976        /*
00977         * the exit code of the process is the exit code of the primordial
00978         * sproc
00979         */
00980        if (!_PR_IS_NATIVE_THREAD(me) && (_PR_MD_CURRENT_CPU()->id == 0)) {
00981               /*
00982                * primordial sproc case: call _exit directly
00983                * Cause SIGKILL to be sent to other sprocs
00984                */
00985               prctl(PR_SETEXITSIG, SIGKILL);
00986               _exit(status);
00987        } else {
00988               int rv;
00989               char data;
00990               sigset_t set;
00991 
00992               /*
00993                * non-primordial sproc case: cause the primordial sproc, cpu 0,
00994                * to wakeup and call _exit
00995                */
00996               _pr_irix_process_exit = 1;
00997               _pr_irix_process_exit_code = status;
00998               rv = write(_pr_irix_primoridal_cpu_fd[1], &data, 1);
00999               PR_ASSERT(rv == 1);
01000               /*
01001                * block all signals and wait for SIGKILL to terminate this sproc
01002                */
01003               sigfillset(&set);
01004               sigsuspend(&set);
01005               /*
01006                * this code doesn't (shouldn't) execute
01007                */
01008               prctl(PR_SETEXITSIG, SIGKILL);
01009               _exit(status);
01010        }
01011 }
01012 
01013 /*
01014  * Override the exit() function in libc to cause the process to exit
01015  * when the primodial/main nspr thread calls exit. Calls to exit by any
01016  * other thread simply result in a call to the exit function in libc.
01017  * The exit code of the process is the exit code of the primordial
01018  * sproc.
01019  */
01020 
01021 void exit(int status)
01022 {
01023 PRThread *me, *thr;
01024 PRCList *qp;
01025 
01026        if (!_pr_initialized)  {
01027               if (!libc_exit) {
01028 
01029                      if (!libc_handle)
01030                             libc_handle = dlopen("libc.so",RTLD_NOW);
01031                      if (libc_handle)
01032                             libc_exit = (void (*)(int)) dlsym(libc_handle, "exit");
01033               }
01034               if (libc_exit)
01035                      (*libc_exit)(status);
01036               else
01037                      _exit(status);
01038        }
01039 
01040        me = _PR_MD_CURRENT_THREAD();
01041 
01042        if (me == NULL)             /* detached thread */
01043               (*libc_exit)(status);
01044 
01045        PR_ASSERT(_PR_IS_NATIVE_THREAD(me) ||
01046                                           (_PR_MD_CURRENT_CPU())->id == me->cpu->id);
01047 
01048        if (me->flags & _PR_PRIMORDIAL) {
01049 
01050               me->flags |= _PR_BOUND_THREAD;     
01051 
01052               PR_ASSERT((_PR_MD_CURRENT_CPU())->id == me->cpu->id);
01053               if (me->cpu->id != 0) {
01054                      _PRCPU *cpu = _pr_primordialCPU;
01055                      PRIntn is;
01056 
01057                      _PR_INTSOFF(is);
01058                      _PR_RUNQ_LOCK(cpu);
01059                      me->cpu = cpu;
01060                      me->state = _PR_RUNNABLE;
01061                      _PR_ADD_RUNQ(me, cpu, me->priority);
01062                      _PR_RUNQ_UNLOCK(cpu);
01063                      _MD_Wakeup_CPUs();
01064 
01065                      _PR_MD_SWITCH_CONTEXT(me);
01066 
01067                      _PR_FAST_INTSON(is);
01068               }
01069 
01070               PR_ASSERT((_PR_MD_CURRENT_CPU())->id == 0);
01071 
01072               if (prctl(PR_GETNSHARE) > 1) {
01073 #define SPROC_EXIT_WAIT_TIME 5
01074                      int sleep_cnt = SPROC_EXIT_WAIT_TIME;
01075 
01076                      /*
01077                       * sprocs still running; caue cpus and recycled global threads
01078                       * to exit
01079                       */
01080                      _pr_irix_exit_now = 1;
01081                      if (_pr_numCPU > 1) {
01082                             _MD_Wakeup_CPUs();
01083                      }
01084                       _PR_DEADQ_LOCK;
01085                       if (_PR_NUM_DEADNATIVE != 0) {
01086                             PRThread *thread;
01087                             PRCList *ptr;
01088 
01089                             ptr = _PR_DEADNATIVEQ.next;
01090                             while( ptr != &_PR_DEADNATIVEQ ) {
01091                                    thread = _PR_THREAD_PTR(ptr);
01092                                    _MD_CVAR_POST_SEM(thread);
01093                                    ptr = ptr->next;
01094                             } 
01095                       }
01096 
01097                      while (sleep_cnt-- > 0) {
01098                             if (waitpid(0, NULL, WNOHANG) >= 0) 
01099                                    sleep(1);
01100                             else
01101                                    break;
01102                      }
01103                      prctl(PR_SETEXITSIG, SIGKILL);
01104               }
01105               (*libc_exit)(status);
01106        } else {
01107               /*
01108                * non-primordial thread; simply call exit in libc.
01109                */
01110               (*libc_exit)(status);
01111        }
01112 }
01113 
01114 
01115 void
01116 _MD_InitRunningCPU(_PRCPU *cpu)
01117 {
01118     extern int _pr_md_pipefd[2];
01119 
01120     _MD_unix_init_running_cpu(cpu);
01121     cpu->md.id = getpid();
01122        _MD_SET_SPROC_PID(getpid());       
01123        if (_pr_md_pipefd[0] >= 0) {
01124        _PR_IOQ_MAX_OSFD(cpu) = _pr_md_pipefd[0];
01125 #ifndef _PR_USE_POLL
01126        FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(cpu));
01127 #endif
01128        }
01129 }
01130 
01131 void
01132 _MD_ExitThread(PRThread *thread)
01133 {
01134     if (thread->flags & _PR_GLOBAL_SCOPE) {
01135         _MD_ATOMIC_DECREMENT(&_pr_md_irix_sprocs);
01136         _MD_CLEAN_THREAD(thread);
01137         _MD_SET_CURRENT_THREAD(NULL);
01138     }
01139 }
01140 
01141 void
01142 _MD_SuspendCPU(_PRCPU *cpu)
01143 {
01144     PRInt32 rv;
01145 
01146        cpu->md.suspending_id = getpid();
01147        rv = kill(cpu->md.id, SIGUSR1);
01148        PR_ASSERT(rv == 0);
01149        /*
01150         * now, block the current thread/cpu until woken up by the suspended
01151         * thread from it's SIGUSR1 signal handler
01152         */
01153        blockproc(getpid());
01154 
01155 }
01156 
01157 void
01158 _MD_ResumeCPU(_PRCPU *cpu)
01159 {
01160     unblockproc(cpu->md.id);
01161 }
01162 
01163 #if 0
01164 /*
01165  * save the register context of a suspended sproc
01166  */
01167 void get_context(PRThread *thr)
01168 {
01169     int len, fd;
01170     char pidstr[24];
01171     char path[24];
01172 
01173     /*
01174      * open the file corresponding to this process in procfs
01175      */
01176     sprintf(path,"/proc/%s","00000");
01177     len = strlen(path);
01178     sprintf(pidstr,"%d",thr->md.id);
01179     len -= strlen(pidstr);
01180     sprintf(path + len,"%s",pidstr);
01181     fd = open(path,O_RDONLY);
01182     if (fd >= 0) {
01183         (void) ioctl(fd, PIOCGREG, thr->md.gregs);
01184         close(fd);
01185     }
01186     return;
01187 }
01188 #endif /* 0 */
01189 
01190 void
01191 _MD_SuspendThread(PRThread *thread)
01192 {
01193     PRInt32 rv;
01194 
01195     PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) &&
01196         _PR_IS_GCABLE_THREAD(thread));
01197 
01198        thread->md.suspending_id = getpid();
01199        rv = kill(thread->md.id, SIGUSR1);
01200        PR_ASSERT(rv == 0);
01201        /*
01202         * now, block the current thread/cpu until woken up by the suspended
01203         * thread from it's SIGUSR1 signal handler
01204         */
01205        blockproc(getpid());
01206 }
01207 
01208 void
01209 _MD_ResumeThread(PRThread *thread)
01210 {
01211     PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) &&
01212         _PR_IS_GCABLE_THREAD(thread));
01213     (void)unblockproc(thread->md.id);
01214 }
01215 
01216 /*
01217  * return the set of processors available for scheduling procs in the
01218  * "mask" argument
01219  */
01220 PRInt32 _MD_GetThreadAffinityMask(PRThread *unused, PRUint32 *mask)
01221 {
01222     PRInt32 nprocs, rv;
01223     struct pda_stat *pstat;
01224 #define MAX_PROCESSORS    32
01225 
01226     nprocs = sysmp(MP_NPROCS);
01227     if (nprocs < 0)
01228         return(-1);
01229     pstat = (struct pda_stat*)PR_MALLOC(sizeof(struct pda_stat) * nprocs);
01230     if (pstat == NULL)
01231         return(-1);
01232     rv = sysmp(MP_STAT, pstat);
01233     if (rv < 0) {
01234         PR_DELETE(pstat);
01235         return(-1);
01236     }
01237     /*
01238      * look at the first 32 cpus
01239      */
01240     nprocs = (nprocs > MAX_PROCESSORS) ? MAX_PROCESSORS : nprocs;
01241     *mask = 0;
01242     while (nprocs) {
01243         if ((pstat->p_flags & PDAF_ENABLED) &&
01244             !(pstat->p_flags & PDAF_ISOLATED)) {
01245             *mask |= (1 << pstat->p_cpuid);
01246         }
01247         nprocs--;
01248         pstat++;
01249     }
01250     return 0;
01251 }
01252 
01253 static char *_thr_state[] = {
01254     "UNBORN",
01255     "RUNNABLE",
01256     "RUNNING",
01257     "LOCK_WAIT",
01258     "COND_WAIT",
01259     "JOIN_WAIT",
01260     "IO_WAIT",
01261     "SUSPENDED",
01262     "DEAD"
01263 };
01264 
01265 void _PR_List_Threads()
01266 {
01267     PRThread *thr;
01268     void *handle;
01269     struct _PRCPU *cpu;
01270     PRCList *qp;
01271     int len, fd;
01272     char pidstr[24];
01273     char path[24];
01274     prpsinfo_t pinfo;
01275 
01276 
01277     printf("\n%s %-s\n"," ","LOCAL Threads");
01278     printf("%s %-s\n"," ","----- -------");
01279     printf("%s %-14s %-10s %-12s %-3s %-10s %-10s %-12s\n\n"," ",
01280         "Thread", "State", "Wait-Handle",
01281         "Cpu","Stk-Base","Stk-Sz","SP");
01282     for (qp = _PR_ACTIVE_LOCAL_THREADQ().next;
01283         qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) {
01284         thr = _PR_ACTIVE_THREAD_PTR(qp);
01285         printf("%s 0x%-12x %-10s "," ",thr,_thr_state[thr->state]);
01286         if (thr->state == _PR_LOCK_WAIT)
01287             handle = thr->wait.lock;
01288         else if (thr->state == _PR_COND_WAIT)
01289             handle = thr->wait.cvar;
01290         else
01291             handle = NULL;
01292         if (handle)
01293             printf("0x%-10x ",handle);
01294         else
01295             printf("%-12s "," ");
01296         printf("%-3d ",thr->cpu->id);
01297         printf("0x%-8x ",thr->stack->stackBottom);
01298         printf("0x%-8x ",thr->stack->stackSize);
01299         printf("0x%-10x\n",thr->md.jb[JB_SP]);
01300     }
01301 
01302     printf("\n%s %-s\n"," ","GLOBAL Threads");
01303     printf("%s %-s\n"," ","------ -------");
01304     printf("%s %-14s %-6s %-12s %-12s %-12s %-12s\n\n"," ","Thread",
01305         "Pid","State","Wait-Handle",
01306         "Stk-Base","Stk-Sz");
01307 
01308     for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next;
01309         qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) {
01310         thr = _PR_ACTIVE_THREAD_PTR(qp);
01311         if (thr->cpu != NULL)
01312             continue;        /* it is a cpu thread */
01313         printf("%s 0x%-12x %-6d "," ",thr,thr->md.id);
01314         /*
01315          * check if the sproc is still running
01316          * first call prctl(PR_GETSHMASK,pid) to check if
01317          * the process is part of the share group (the pid
01318          * could have been recycled by the OS)
01319          */
01320         if (prctl(PR_GETSHMASK,thr->md.id) < 0) {
01321             printf("%-12s\n","TERMINATED");
01322             continue;
01323         }
01324         /*
01325          * Now, check if the sproc terminated and is in zombie
01326          * state
01327          */
01328         sprintf(path,"/proc/pinfo/%s","00000");
01329         len = strlen(path);
01330         sprintf(pidstr,"%d",thr->md.id);
01331         len -= strlen(pidstr);
01332         sprintf(path + len,"%s",pidstr);
01333         fd = open(path,O_RDONLY);
01334         if (fd >= 0) {
01335             if (ioctl(fd, PIOCPSINFO, &pinfo) < 0)
01336                 printf("%-12s ","TERMINATED");
01337             else if (pinfo.pr_zomb)
01338                 printf("%-12s ","TERMINATED");
01339             else
01340                 printf("%-12s ",_thr_state[thr->state]);
01341             close(fd);
01342         } else {
01343             printf("%-12s ","TERMINATED");
01344         }
01345 
01346         if (thr->state == _PR_LOCK_WAIT)
01347             handle = thr->wait.lock;
01348         else if (thr->state == _PR_COND_WAIT)
01349             handle = thr->wait.cvar;
01350         else
01351             handle = NULL;
01352         if (handle)
01353             printf("%-12x ",handle);
01354         else
01355             printf("%-12s "," ");
01356         printf("0x%-10x ",thr->stack->stackBottom);
01357         printf("0x%-10x\n",thr->stack->stackSize);
01358     }
01359 
01360     printf("\n%s %-s\n"," ","CPUs");
01361     printf("%s %-s\n"," ","----");
01362     printf("%s %-14s %-6s %-12s \n\n"," ","Id","Pid","State");
01363 
01364 
01365     for (qp = _PR_CPUQ().next; qp != &_PR_CPUQ(); qp = qp->next) {
01366         cpu = _PR_CPU_PTR(qp);
01367         printf("%s %-14d %-6d "," ",cpu->id,cpu->md.id);
01368         /*
01369          * check if the sproc is still running
01370          * first call prctl(PR_GETSHMASK,pid) to check if
01371          * the process is part of the share group (the pid
01372          * could have been recycled by the OS)
01373          */
01374         if (prctl(PR_GETSHMASK,cpu->md.id) < 0) {
01375             printf("%-12s\n","TERMINATED");
01376             continue;
01377         }
01378         /*
01379          * Now, check if the sproc terminated and is in zombie
01380          * state
01381          */
01382         sprintf(path,"/proc/pinfo/%s","00000");
01383         len = strlen(path);
01384         sprintf(pidstr,"%d",cpu->md.id);
01385         len -= strlen(pidstr);
01386         sprintf(path + len,"%s",pidstr);
01387         fd = open(path,O_RDONLY);
01388         if (fd >= 0) {
01389             if (ioctl(fd, PIOCPSINFO, &pinfo) < 0)
01390                 printf("%-12s\n","TERMINATED");
01391             else if (pinfo.pr_zomb)
01392                 printf("%-12s\n","TERMINATED");
01393             else
01394                 printf("%-12s\n","RUNNING");
01395             close(fd);
01396         } else {
01397             printf("%-12s\n","TERMINATED");
01398         }
01399 
01400     }
01401     fflush(stdout);
01402 }
01403 #endif /* defined(_PR_PTHREADS) */ 
01404 
01405 PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
01406 {
01407 #if !defined(_PR_PTHREADS)
01408     if (isCurrent) {
01409         (void) setjmp(t->md.jb);
01410     }
01411     *np = sizeof(t->md.jb) / sizeof(PRWord);
01412     return (PRWord *) (t->md.jb);
01413 #else
01414        *np = 0;
01415        return NULL;
01416 #endif
01417 }
01418 
01419 void _MD_EarlyInit(void)
01420 {
01421 #if !defined(_PR_PTHREADS)
01422     char *eval;
01423     int fd;
01424        extern int __ateachexit(void (*func)(void));
01425 
01426     sigemptyset(&ints_off);
01427     sigaddset(&ints_off, SIGALRM);
01428     sigaddset(&ints_off, SIGIO);
01429     sigaddset(&ints_off, SIGCLD);
01430 
01431     if (eval = getenv("_NSPR_TERMINATE_ON_ERROR"))
01432         _nspr_terminate_on_error = (0 == atoi(eval) == 0) ? PR_FALSE : PR_TRUE;
01433 
01434     fd = open("/dev/zero",O_RDWR , 0);
01435     if (fd < 0) {
01436         perror("open /dev/zero failed");
01437         exit(1);
01438     }
01439     /*
01440      * Set up the sproc private data area.
01441      * This region exists at the same address, _nspr_sproc_private, for
01442      * every sproc, but each sproc gets a private copy of the region.
01443      */
01444     _nspr_sproc_private = (char*)mmap(0, _pr_pageSize, PROT_READ | PROT_WRITE,
01445         MAP_PRIVATE| MAP_LOCAL, fd, 0);
01446     if (_nspr_sproc_private == (void*)-1) {
01447         perror("mmap /dev/zero failed");
01448         exit(1);
01449     }
01450        _MD_SET_SPROC_PID(getpid());       
01451     close(fd);
01452        __ateachexit(irix_detach_sproc);
01453 #endif
01454     _MD_IrixIntervalInit();
01455 }  /* _MD_EarlyInit */
01456 
01457 void _MD_IrixInit(void)
01458 {
01459 #if !defined(_PR_PTHREADS)
01460     struct sigaction sigact;
01461     PRThread *me = _PR_MD_CURRENT_THREAD();
01462        int rv;
01463 
01464 #ifdef _PR_HAVE_SGI_PRDA_PROCMASK
01465        /*
01466         * enable user-level processing of sigprocmask(); this is an undocumented
01467         * feature available in Irix 6.2, 6.3, 6.4 and 6.5
01468         */
01469        __sgi_prda_procmask(USER_LEVEL);
01470 #endif
01471 
01472        /*
01473         * set up SIGUSR1 handler; this is used to save state
01474         * during PR_SuspendAll
01475         */
01476        sigact.sa_handler = save_context_and_block;
01477        sigact.sa_flags = SA_RESTART;
01478        sigact.sa_mask = ints_off;
01479        sigaction(SIGUSR1, &sigact, 0);
01480 
01481     /*
01482      * Change the name of the core file from core to core.pid,
01483      * This is inherited by the sprocs created by this process
01484      */
01485 #ifdef PR_COREPID
01486     prctl(PR_COREPID, 0, 1);
01487 #endif
01488     /*
01489      * Irix-specific terminate on error processing
01490      */
01491        /*
01492         * PR_SETABORTSIG is a new command implemented in a patch to
01493         * Irix 6.2, 6.3 and 6.4. This causes a signal to be sent to all
01494         * sprocs in the process when one of them terminates abnormally
01495         *
01496         */
01497        if (prctl(PR_SETABORTSIG, SIGKILL) < 0) {
01498               /*
01499                *  if (errno == EINVAL)
01500                *
01501                *     PR_SETABORTSIG not supported under this OS.
01502                *     You may want to get a recent kernel rollup patch that
01503                *     supports this feature.
01504                *
01505                */
01506        }
01507        /*
01508         * PR_SETEXITSIG -  send the SIGCLD signal to the parent
01509         *            sproc when any sproc terminates
01510         *
01511         *    This is used to cause the entire application to
01512         *    terminate when    any sproc terminates abnormally by
01513         *     receipt of a SIGSEGV, SIGBUS or SIGABRT signal.
01514         *    If this is not done, the application may seem
01515         *     "hung" to the user because the other sprocs may be
01516         *    waiting for resources held by the
01517         *    abnormally-terminating sproc.
01518         */
01519        prctl(PR_SETEXITSIG, 0);
01520 
01521        sigact.sa_handler = sigchld_handler;
01522        sigact.sa_flags = SA_RESTART;
01523        sigact.sa_mask = ints_off;
01524        sigaction(SIGCLD, &sigact, NULL);
01525 
01526     /*
01527      * setup stack fields for the primordial thread
01528      */
01529     me->stack->stackSize = prctl(PR_GETSTACKSIZE);
01530     me->stack->stackBottom = me->stack->stackTop - me->stack->stackSize;
01531 
01532     rv = pipe(_pr_irix_primoridal_cpu_fd);
01533     PR_ASSERT(rv == 0);
01534 #ifndef _PR_USE_POLL
01535     _PR_IOQ_MAX_OSFD(me->cpu) = _pr_irix_primoridal_cpu_fd[0];
01536     FD_SET(_pr_irix_primoridal_cpu_fd[0], &_PR_FD_READ_SET(me->cpu));
01537 #endif
01538 
01539        libc_handle = dlopen("libc.so",RTLD_NOW);
01540        PR_ASSERT(libc_handle != NULL);
01541        libc_exit = (void (*)(int)) dlsym(libc_handle, "exit");
01542        PR_ASSERT(libc_exit != NULL);
01543        /* dlclose(libc_handle); */
01544 
01545 #endif /* _PR_PTHREADS */
01546 
01547     _PR_UnixInit();
01548 }
01549 
01550 /**************************************************************************/
01551 /************** code and such for NSPR 2.0's interval times ***************/
01552 /**************************************************************************/
01553 
01554 #define PR_PSEC_PER_SEC 1000000000000ULL  /* 10^12 */
01555 
01556 #ifndef SGI_CYCLECNTR_SIZE
01557 #define SGI_CYCLECNTR_SIZE      165     /* Size user needs to use to read CC */
01558 #endif
01559 
01560 static PRIntn mmem_fd = -1;
01561 static PRIntn clock_width = 0;
01562 static void *iotimer_addr = NULL;
01563 static PRUint32 pr_clock_mask = 0;
01564 static PRUint32 pr_clock_shift = 0;
01565 static PRIntervalTime pr_ticks = 0;
01566 static PRUint32 pr_clock_granularity = 1;
01567 static PRUint32 pr_previous = 0, pr_residual = 0;
01568 static PRUint32 pr_ticks_per_second = 0;
01569 
01570 extern PRIntervalTime _PR_UNIX_GetInterval(void);
01571 extern PRIntervalTime _PR_UNIX_TicksPerSecond(void);
01572 
01573 static void _MD_IrixIntervalInit(void)
01574 {
01575     /*
01576      * As much as I would like, the service available through this
01577      * interface on R3000's (aka, IP12) just isn't going to make it.
01578      * The register is only 24 bits wide, and rolls over at a verocious
01579      * rate.
01580      */
01581     PRUint32 one_tick = 0;
01582     struct utsname utsinfo;
01583     uname(&utsinfo);
01584     if ((strncmp("IP12", utsinfo.machine, 4) != 0)
01585         && ((mmem_fd = open("/dev/mmem", O_RDONLY)) != -1))
01586     {
01587         int poffmask = getpagesize() - 1;
01588         __psunsigned_t phys_addr, raddr, cycleval;
01589 
01590         phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval);
01591         raddr = phys_addr & ~poffmask;
01592         iotimer_addr = mmap(
01593             0, poffmask, PROT_READ, MAP_PRIVATE, mmem_fd, (__psint_t)raddr);
01594 
01595         clock_width = syssgi(SGI_CYCLECNTR_SIZE);
01596         if (clock_width < 0)
01597         {
01598             /* 
01599              * We must be executing on a 6.0 or earlier system, since the
01600              * SGI_CYCLECNTR_SIZE call is not supported.
01601              * 
01602              * The only pre-6.1 platforms with 64-bit counters are
01603              * IP19 and IP21 (Challenge, PowerChallenge, Onyx).
01604              */
01605             if (!strncmp(utsinfo.machine, "IP19", 4) ||
01606                 !strncmp(utsinfo.machine, "IP21", 4))
01607                 clock_width = 64;
01608             else
01609                 clock_width = 32;
01610         }
01611 
01612         /*
01613          * 'cycleval' is picoseconds / increment of the counter.
01614          * I'm pushing for a tick to be 100 microseconds, 10^(-4).
01615          * That leaves 10^(-8) left over, or 10^8 / cycleval.
01616          * Did I do that right?
01617          */
01618 
01619         one_tick =  100000000UL / cycleval ;  /* 100 microseconds */
01620 
01621         while (0 != one_tick)
01622         {
01623             pr_clock_shift += 1;
01624             one_tick = one_tick >> 1;
01625             pr_clock_granularity = pr_clock_granularity << 1;
01626         }
01627         pr_clock_mask = pr_clock_granularity - 1;  /* to make a mask out of it */
01628         pr_ticks_per_second = PR_PSEC_PER_SEC
01629                 / ((PRUint64)pr_clock_granularity * (PRUint64)cycleval);
01630             
01631         iotimer_addr = (void*)
01632             ((__psunsigned_t)iotimer_addr + (phys_addr & poffmask));
01633     }
01634     else
01635     {
01636         pr_ticks_per_second = _PR_UNIX_TicksPerSecond();
01637     }
01638 }  /* _MD_IrixIntervalInit */
01639 
01640 PRIntervalTime _MD_IrixIntervalPerSec(void)
01641 {
01642     return pr_ticks_per_second;
01643 }
01644 
01645 PRIntervalTime _MD_IrixGetInterval(void)
01646 {
01647     if (mmem_fd != -1)
01648     {
01649         if (64 == clock_width)
01650         {
01651             PRUint64 temp = *(PRUint64*)iotimer_addr;
01652             pr_ticks = (PRIntervalTime)(temp >> pr_clock_shift);
01653         }
01654         else
01655         {
01656             PRIntervalTime ticks = pr_ticks;
01657             PRUint32 now = *(PRUint32*)iotimer_addr, temp;
01658             PRUint32 residual = pr_residual, previous = pr_previous;
01659 
01660             temp = now - previous + residual;
01661             residual = temp & pr_clock_mask;
01662             ticks += temp >> pr_clock_shift;
01663 
01664             pr_previous = now;
01665             pr_residual = residual;
01666             pr_ticks = ticks;
01667         }
01668     }
01669     else
01670     {
01671         /*
01672          * No fast access. Use the time of day clock. This isn't the
01673          * right answer since this clock can get set back, tick at odd
01674          * rates, and it's expensive to acqurie.
01675          */
01676         pr_ticks = _PR_UNIX_GetInterval();
01677     }
01678     return pr_ticks;
01679 }  /* _MD_IrixGetInterval */
01680