home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / md / unix / irix.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  34.8 KB  |  1,309 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "primpl.h"
  20.  
  21. #include <signal.h>
  22.  
  23. #include <sys/types.h>
  24. #include <fcntl.h>
  25. #include <unistd.h>
  26. #include <string.h>
  27. #include <sys/mman.h>
  28. #include <sys/syssgi.h>
  29. #include <sys/time.h>
  30. #include <sys/immu.h>
  31. #include <sys/utsname.h>
  32. #include <sys/sysmp.h>
  33. #include <sys/pda.h>
  34. #include <sys/prctl.h>
  35. #include <sys/wait.h>
  36. #include <sys/resource.h>
  37. #include <sys/procfs.h>
  38. #include <task.h>
  39.  
  40. static void _MD_IntervalInit(void);
  41.  
  42. #if defined(_PR_PTHREADS)
  43. #else  /* defined(_PR_PTHREADS) */
  44.  
  45. char *_nspr_sproc_private;    /* ptr. to private region in every sproc */
  46.  
  47. extern PRUintn    _pr_numCPU;
  48.  
  49. typedef struct nspr_arena {
  50.     PRCList links;
  51.     usptr_t *usarena;
  52. } nspr_arena;
  53.  
  54. #define ARENA_PTR(qp) \
  55.     ((nspr_arena *) ((char*) (qp) - offsetof(nspr_arena , links)))
  56.  
  57. static usptr_t *alloc_new_arena(void);
  58.  
  59. PRCList arena_list = PR_INIT_STATIC_CLIST(&arena_list);
  60. ulock_t arena_list_lock;
  61. nspr_arena first_arena;
  62. int    _nspr_irix_arena_cnt = 1;
  63.  
  64. long    _nspr_irix_lock_cnt = 0;
  65. long    _nspr_irix_sem_cnt = 0;
  66. long    _nspr_irix_pollsem_cnt = 0;
  67.  
  68. usptr_t *_pr_usArena;
  69. ulock_t _pr_heapLock;
  70.  
  71. usema_t *_pr_irix_exit_sem;
  72. PRInt32 _pr_irix_exit_now = 0;
  73.  
  74.  
  75. #define _NSPR_DEF_INITUSERS        100    /* default value of CONF_INITUSERS */
  76. #define _NSPR_DEF_INITSIZE        (4 * 1024 * 1024)    /* 4 MB */
  77.  
  78. int _irix_initusers = _NSPR_DEF_INITUSERS;
  79. int _irix_initsize = _NSPR_DEF_INITSIZE;
  80.  
  81. PRIntn _pr_io_in_progress, _pr_clock_in_progress;
  82.  
  83. PRInt32 _pr_md_irix_sprocs_created, _pr_md_irix_sprocs_failed;
  84. PRInt32 _pr_md_irix_sprocs = 1;
  85. PRCList _pr_md_irix_sproc_list =
  86. PR_INIT_STATIC_CLIST(&_pr_md_irix_sproc_list);
  87.  
  88. sigset_t ints_off;
  89. extern sigset_t timer_set;
  90.  
  91. #if !defined(PR_SETABORTSIG)
  92. #define PR_SETABORTSIG 18
  93. #endif
  94. /*
  95.  * terminate the entire application if any sproc exits abnormally
  96.  */
  97. PRBool _nspr_terminate_on_error = PR_TRUE;
  98.  
  99. /*
  100.  * exported interface to set the shared arena parameters
  101.  */
  102. void _PR_Irix_Set_Arena_Params(PRInt32 initusers, PRInt32 initsize)
  103. {
  104.     _irix_initusers = initusers;
  105.     _irix_initsize = initsize;
  106. }
  107.  
  108. static usptr_t *alloc_new_arena()
  109. {
  110.     return(usinit("/dev/zero"));
  111. }
  112.  
  113. static PRStatus new_poll_sem(struct _MDThread *mdthr, int val)
  114. {
  115. PRIntn _is;
  116. PRStatus rv = PR_SUCCESS;
  117. usema_t *sem = NULL;
  118. PRCList *qp;
  119. nspr_arena *arena;
  120. usptr_t *irix_arena;
  121. PRThread *me = _PR_MD_CURRENT_THREAD();
  122.  
  123.     if (me && !_PR_IS_NATIVE_THREAD(me))
  124.         _PR_INTSOFF(_is); 
  125.     _PR_LOCK(arena_list_lock);
  126.     for (qp = arena_list.next; qp != &arena_list; qp = qp->next) {
  127.         arena = ARENA_PTR(qp);
  128.         sem = usnewpollsema(arena->usarena, val);
  129.         if (sem != NULL) {
  130.             mdthr->cvar_pollsem = sem;
  131.             mdthr->pollsem_arena = arena->usarena;
  132.             break;
  133.         }
  134.     }
  135.     if (sem == NULL) {
  136.         /*
  137.          * If no space left in the arena allocate a new one.
  138.          */
  139.         if (errno == ENOMEM) {
  140.             arena = PR_NEWZAP(nspr_arena);
  141.             if (arena != NULL) {
  142.                 irix_arena = alloc_new_arena();
  143.                 if (irix_arena) {
  144.                     PR_APPEND_LINK(&arena->links, &arena_list);
  145.                     _nspr_irix_arena_cnt++;
  146.                     arena->usarena = irix_arena;
  147.                     sem = usnewpollsema(arena->usarena, val);
  148.                     if (sem != NULL) {
  149.                         mdthr->cvar_pollsem = sem;
  150.                         mdthr->pollsem_arena = arena->usarena;
  151.                     } else
  152.                         rv = PR_FAILURE;
  153.                 } else {
  154.                     PR_DELETE(arena);
  155.                     rv = PR_FAILURE;
  156.                 }
  157.  
  158.             } else
  159.                 rv = PR_FAILURE;
  160.         } else
  161.             rv = PR_FAILURE;
  162.     }
  163.     _PR_UNLOCK(arena_list_lock);
  164.     if (me && !_PR_IS_NATIVE_THREAD(me))
  165.         _PR_FAST_INTSON(_is);
  166.     if (rv == PR_SUCCESS)
  167.         _MD_ATOMIC_INCREMENT(&_nspr_irix_pollsem_cnt);
  168.     return rv;
  169. }
  170.  
  171. static void free_poll_sem(struct _MDThread *mdthr)
  172. {
  173. PRIntn _is;
  174. PRThread *me = _PR_MD_CURRENT_THREAD();
  175.  
  176.     if (me && !_PR_IS_NATIVE_THREAD(me))
  177.         _PR_INTSOFF(_is); 
  178.     usfreepollsema(mdthr->cvar_pollsem, mdthr->pollsem_arena);
  179.     if (me && !_PR_IS_NATIVE_THREAD(me))
  180.         _PR_FAST_INTSON(_is);
  181.     _MD_ATOMIC_DECREMENT(&_nspr_irix_pollsem_cnt);
  182. }
  183.  
  184. static PRStatus new_lock(struct _MDLock *lockp)
  185. {
  186. PRIntn _is;
  187. PRStatus rv = PR_SUCCESS;
  188. ulock_t lock = NULL;
  189. PRCList *qp;
  190. nspr_arena *arena;
  191. usptr_t *irix_arena;
  192. PRThread *me = _PR_MD_CURRENT_THREAD();
  193.  
  194.     if (me && !_PR_IS_NATIVE_THREAD(me))
  195.         _PR_INTSOFF(_is); 
  196.     _PR_LOCK(arena_list_lock);
  197.     for (qp = arena_list.next; qp != &arena_list; qp = qp->next) {
  198.         arena = ARENA_PTR(qp);
  199.         lock = usnewlock(arena->usarena);
  200.         if (lock != NULL) {
  201.             lockp->lock = lock;
  202.             lockp->arena = arena->usarena;
  203.             break;
  204.         }
  205.     }
  206.     if (lock == NULL) {
  207.         /*
  208.          * If no space left in the arena allocate a new one.
  209.          */
  210.         if (errno == ENOMEM) {
  211.             arena = PR_NEWZAP(nspr_arena);
  212.             if (arena != NULL) {
  213.                 irix_arena = alloc_new_arena();
  214.                 if (irix_arena) {
  215.                     PR_APPEND_LINK(&arena->links, &arena_list);
  216.                     _nspr_irix_arena_cnt++;
  217.                     arena->usarena = irix_arena;
  218.                     lock = usnewlock(irix_arena);
  219.                     if (lock != NULL) {
  220.                         lockp->lock = lock;
  221.                         lockp->arena = arena->usarena;
  222.                     } else
  223.                         rv = PR_FAILURE;
  224.                 } else {
  225.                     PR_DELETE(arena);
  226.                     rv = PR_FAILURE;
  227.                 }
  228.  
  229.             } else
  230.                 rv = PR_FAILURE;
  231.         } else
  232.             rv = PR_FAILURE;
  233.     }
  234.     _PR_UNLOCK(arena_list_lock);
  235.     if (me && !_PR_IS_NATIVE_THREAD(me))
  236.         _PR_FAST_INTSON(_is);
  237.     if (rv == PR_SUCCESS)
  238.         _MD_ATOMIC_INCREMENT(&_nspr_irix_lock_cnt);
  239.     return rv;
  240. }
  241.  
  242. static void free_lock(struct _MDLock *lockp)
  243. {
  244. PRIntn _is;
  245. PRThread *me = _PR_MD_CURRENT_THREAD();
  246.  
  247.     if (me && !_PR_IS_NATIVE_THREAD(me))
  248.         _PR_INTSOFF(_is); 
  249.     usfreelock(lockp->lock, lockp->arena);
  250.     if (me && !_PR_IS_NATIVE_THREAD(me))
  251.         _PR_FAST_INTSON(_is);
  252.     _MD_ATOMIC_DECREMENT(&_nspr_irix_lock_cnt);
  253. }
  254.  
  255. void _MD_FREE_LOCK(struct _MDLock *lockp)
  256. {
  257.     PRIntn _is;
  258.     PRThread *me = _PR_MD_CURRENT_THREAD();
  259.  
  260.     if (me && !_PR_IS_NATIVE_THREAD(me))
  261.         _PR_INTSOFF(_is); 
  262.     free_lock(lockp);
  263.     if (me && !_PR_IS_NATIVE_THREAD(me))
  264.         _PR_FAST_INTSON(_is);
  265. }
  266.  
  267. /*
  268.  * _MD_get_attached_thread
  269.  *        Return the thread pointer of the current thread if it is attached.
  270.  *
  271.  *        This function is needed for Irix because the thread-local-storage is
  272.  *        implemented by mmapin'g a page with the MAP_LOCAL flag. This causes the
  273.  *        sproc-private page to inherit contents of the page of the caller of sproc().
  274.  */
  275. PRThread *_MD_get_attached_thread(void)
  276. {
  277.     if (_MD_GET_SPROC_PID() == getpid())
  278.         return _PR_MD_CURRENT_THREAD();
  279.     else
  280.         return 0;
  281. }
  282.  
  283. PRStatus _MD_NEW_LOCK(struct _MDLock *lockp)
  284. {
  285.     PRStatus rv;
  286.     PRIntn is;
  287.     PRThread *me = _PR_MD_CURRENT_THREAD();    
  288.  
  289.     if (me && !_PR_IS_NATIVE_THREAD(me))
  290.         _PR_INTSOFF(is);
  291.     rv = new_lock(lockp);
  292.     if (me && !_PR_IS_NATIVE_THREAD(me))
  293.         _PR_FAST_INTSON(is);
  294.     return rv;
  295. }
  296.  
  297. static void
  298. sigchld_handler(int sig)
  299. {
  300.     pid_t pid;
  301.     int status;
  302.  
  303.     /*
  304.      * If an sproc exited abnormally send a SIGKILL signal to all the
  305.      * sprocs in the process to terminate the application
  306.      */
  307.     while ((pid = waitpid(0, &status, WNOHANG)) > 0) {
  308.         if (WIFSIGNALED(status) && ((WTERMSIG(status) == SIGSEGV) ||
  309.             (WTERMSIG(status) == SIGBUS) ||
  310.             (WTERMSIG(status) == SIGABRT) ||
  311.             (WTERMSIG(status) == SIGILL)))
  312.  
  313.             prctl(PR_SETEXITSIG, SIGKILL);
  314.             exit(status);
  315.     }
  316. }
  317.  
  318. static void save_context_and_block(int sig)
  319. {
  320. PRThread *me = _PR_MD_CURRENT_THREAD();
  321. _PRCPU *cpu = _PR_MD_CURRENT_CPU();
  322.  
  323.     /*
  324.      * save context
  325.      */
  326.     (void) setjmp(me->md.jb);
  327.     /*
  328.      * unblock the suspending thread
  329.      */
  330.     if (me->cpu) {
  331.         /*
  332.          * I am a cpu thread, not a user-created GLOBAL thread
  333.          */
  334.         unblockproc(cpu->md.suspending_id);    
  335.     } else {
  336.         unblockproc(me->md.suspending_id);    
  337.     }
  338.     /*
  339.      * now, block current thread
  340.      */
  341.     blockproc(getpid());
  342. }
  343.  
  344. /*
  345. ** The irix kernel has a bug in it which causes async connect's which are
  346. ** interrupted by a signal to fail terribly (EADDRINUSE is returned). 
  347. ** We work around the bug by blocking signals during the async connect
  348. ** attempt.
  349. */
  350. PRInt32 _MD_irix_connect(
  351.     PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen, PRIntervalTime timeout)
  352. {
  353.     PRInt32 rv;
  354.     sigset_t oldset;
  355.  
  356.     sigprocmask(SIG_BLOCK, &ints_off, &oldset);
  357.     rv = connect(osfd, addr, addrlen);
  358.     sigprocmask(SIG_SETMASK, &oldset, 0);
  359.  
  360.     return(rv);
  361. }
  362.  
  363. #include "prprf.h"
  364.  
  365. /********************************************************************/
  366. /********************************************************************/
  367. /*************** Various thread like things for IRIX ****************/
  368. /********************************************************************/
  369. /********************************************************************/
  370.  
  371. void *_MD_GetSP(PRThread *t)
  372. {
  373.     PRThread *me = _PR_MD_CURRENT_THREAD();
  374.     void *sp;
  375.  
  376.     if (me == t)
  377.         (void) setjmp(t->md.jb);
  378.  
  379.     sp = (void *)(t->md.jb[JB_SP]);
  380.     PR_ASSERT((sp >= (void *) t->stack->stackBottom) &&
  381.         (sp <= (void *) (t->stack->stackBottom + t->stack->stackSize)));
  382.     return(sp);
  383. }
  384.  
  385. void _MD_InitLocks()
  386. {
  387.     char buf[200];
  388.     char *init_users, *init_size;
  389.  
  390.     PR_snprintf(buf, sizeof(buf), "/dev/zero");
  391.  
  392.     if (init_users = getenv("_NSPR_IRIX_INITUSERS"))
  393.         _irix_initusers = atoi(init_users);
  394.  
  395.     if (init_size = getenv("_NSPR_IRIX_INITSIZE"))
  396.         _irix_initsize = atoi(init_size);
  397.  
  398.     usconfig(CONF_INITUSERS, _irix_initusers);
  399.     usconfig(CONF_INITSIZE, _irix_initsize);
  400.     usconfig(CONF_AUTOGROW, 1);
  401.     usconfig(CONF_AUTORESV, 1);
  402.     if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0) {
  403.         perror("PR_Init: unable to config mutex arena");
  404.         exit(-1);
  405.     }
  406.  
  407.     _pr_usArena = usinit(buf);
  408.     if (!_pr_usArena) {
  409.         fprintf(stderr,
  410.             "PR_Init: Error - unable to create lock/monitor arena\n");
  411.         exit(-1);
  412.     }
  413.     _pr_heapLock = usnewlock(_pr_usArena);
  414.  
  415.     arena_list_lock = usnewlock(_pr_usArena);
  416.     _nspr_irix_lock_cnt = 3;
  417.  
  418.     _pr_irix_exit_sem = usnewsema(_pr_usArena, 0);
  419.     _nspr_irix_sem_cnt = 1;
  420.  
  421.     first_arena.usarena = _pr_usArena;
  422.     PR_INIT_CLIST(&first_arena.links);
  423.     PR_APPEND_LINK(&first_arena.links, &arena_list);
  424. }
  425.  
  426. /* _PR_IRIX_CHILD_PROCESS is a private API for Server group */
  427. void _PR_IRIX_CHILD_PROCESS()
  428. {
  429.     PR_ASSERT(_PR_MD_CURRENT_CPU() == _pr_primordialCPU);
  430.     PR_ASSERT(_pr_numCPU == 1);
  431.     PR_ASSERT((_pr_userActive + _pr_systemActive) == 2);
  432.     /*
  433.      * save the new pid
  434.      */
  435.     _pr_primordialCPU->md.id = getpid();
  436. }
  437.  
  438. static PRStatus pr_cvar_wait_sem(PRThread *thread, PRIntervalTime timeout)
  439. {
  440.     struct timeval tv, *tvp;
  441.     fd_set rd;
  442.     int rv;
  443.  
  444.     if(timeout == PR_INTERVAL_NO_TIMEOUT) tvp = NULL;
  445.     else {
  446.         tv.tv_sec = PR_IntervalToSeconds(timeout);
  447.         tv.tv_usec = PR_IntervalToMicroseconds(
  448.             timeout - PR_SecondsToInterval(tv.tv_sec));
  449.         tvp = &tv;
  450.     }
  451.     FD_ZERO(&rd);
  452.     FD_SET(thread->md.cvar_pollsemfd, &rd);
  453.     /*
  454.      * call uspsema only if a previous select call on this semaphore
  455.      * did not timeout
  456.      */
  457.     if (!thread->md.cvar_pollsem_select) {
  458.         rv = _PR_WAIT_SEM(thread->md.cvar_pollsem);
  459.         PR_ASSERT(rv >= 0);
  460.     } else
  461.         rv = 0;
  462. again:
  463.     if(!rv) {
  464.         rv = _MD_SELECT(thread->md.cvar_pollsemfd + 1, &rd,
  465.             NULL,NULL,tvp);
  466.         if ((rv == -1) && (errno == EINTR)) {
  467.             rv = 0;
  468.             goto again;
  469.         }
  470.         PR_ASSERT(rv >= 0);
  471.     }
  472.  
  473.     if (rv > 0) {
  474.         /*
  475.          * acquired the semaphore, call uspsema next time
  476.          */
  477.         thread->md.cvar_pollsem_select = 0;
  478.         return PR_SUCCESS;
  479.     } else {
  480.         /*
  481.          * select timed out; must call select, not uspsema, when trying
  482.          * to acquire the semaphore the next time
  483.          */
  484.         thread->md.cvar_pollsem_select = 1;
  485.         return PR_FAILURE;
  486.     }
  487. }
  488.  
  489. PRStatus _MD_wait(PRThread *thread, PRIntervalTime ticks)
  490. {
  491.     if ( thread->flags & _PR_GLOBAL_SCOPE ) {
  492.     _MD_CHECK_FOR_EXIT();
  493.         if (pr_cvar_wait_sem(thread, ticks) == PR_FAILURE) {
  494.         _MD_CHECK_FOR_EXIT();
  495.             /*
  496.              * wait timed out
  497.              */
  498.             _PR_THREAD_LOCK(thread);
  499.             if (thread->wait.cvar) {
  500.                 /*
  501.                  * The thread will remove itself from the waitQ
  502.                  * of the cvar in _PR_WaitCondVar
  503.                  */
  504.                 thread->wait.cvar = NULL;
  505.                 thread->state =  _PR_RUNNING;
  506.                 _PR_THREAD_UNLOCK(thread);
  507.             }  else {
  508.                 _PR_THREAD_UNLOCK(thread);
  509.                 /*
  510.              * This thread was woken up by a notifying thread
  511.              * at the same time as a timeout; so, consume the
  512.              * extra post operation on the semaphore
  513.              */
  514.             _MD_CHECK_FOR_EXIT();
  515.             pr_cvar_wait_sem(thread, PR_INTERVAL_NO_TIMEOUT);
  516.             }
  517.         _MD_CHECK_FOR_EXIT();
  518.         }
  519.     } else {
  520.         _PR_MD_SWITCH_CONTEXT(thread);
  521.     }
  522.     return PR_SUCCESS;
  523. }
  524.  
  525. PRStatus _MD_WakeupWaiter(PRThread *thread)
  526. {
  527.     PRThread *me = _PR_MD_CURRENT_THREAD();
  528.     PRInt32 pid, rv;
  529.     PRIntn is;
  530.  
  531.     PR_ASSERT(_pr_md_idle_cpus >= 0);
  532.     if (thread == NULL) {
  533.         if (_pr_md_idle_cpus)
  534.             _MD_Wakeup_CPUs();
  535.     } else if (!_PR_IS_NATIVE_THREAD(thread)) {
  536.         if (_pr_md_idle_cpus)
  537.                _MD_Wakeup_CPUs();
  538.     } else {
  539.         PR_ASSERT(_PR_IS_NATIVE_THREAD(thread));
  540.         if (!_PR_IS_NATIVE_THREAD(me))
  541.             _PR_INTSOFF(is);
  542.         _MD_CVAR_POST_SEM(thread);
  543.         if (!_PR_IS_NATIVE_THREAD(me))
  544.             _PR_FAST_INTSON(is);
  545.     } 
  546.     return PR_SUCCESS;
  547. }
  548.  
  549. PRStatus _MD_CreateThread(PRThread *thread, 
  550. void (*start)(void *), 
  551. PRThreadPriority priority, 
  552. PRThreadScope scope, 
  553. PRThreadState state, 
  554. PRUint32 stackSize)
  555. {
  556.     typedef void (*SprocEntry) (void *, size_t);
  557.     SprocEntry spentry = (SprocEntry)start;
  558.     PRIntn is;
  559.     PRThread *me = _PR_MD_CURRENT_THREAD();    
  560.     PRInt32 pid;
  561.     PRStatus rv;
  562.  
  563.     if (!_PR_IS_NATIVE_THREAD(me))
  564.         _PR_INTSOFF(is);
  565.     thread->md.cvar_pollsem_select = 0;
  566.     thread->flags |= _PR_GLOBAL_SCOPE;
  567.     pid = sprocsp(
  568.                     spentry,            /* startup func    */
  569.                     PR_SALL,            /* attribute flags     */
  570.                     (void *)thread,     /* thread param     */
  571.                     NULL,               /* stack address    */
  572.                     stackSize);         /* stack size     */
  573.     if (pid > 0) {
  574.         /*
  575.          * Wait for the sproc to signal me after it has initialized
  576.          * itself
  577.          */
  578.         if (!_PR_IS_NATIVE_THREAD(me))
  579.             blockproc(me->cpu->md.id);
  580.         else
  581.             blockproc(me->md.id);
  582.         if (thread->md.cvar_pollsemfd < 0) {
  583.             /*
  584.              * the sproc failed to create a polled semaphore and exited
  585.              */
  586.             _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs_failed);
  587.             rv = PR_FAILURE;
  588.         } else {
  589.             _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs_created);
  590.             _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs);
  591.             rv = PR_SUCCESS;
  592.         }
  593.         if (!_PR_IS_NATIVE_THREAD(me))
  594.             _PR_FAST_INTSON(is);
  595.         return rv;
  596.     } else {
  597.         _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs_failed);
  598.         if (!_PR_IS_NATIVE_THREAD(me))
  599.             _PR_FAST_INTSON(is);
  600.         return PR_FAILURE;
  601.     }
  602. }
  603.  
  604. void _MD_CleanThread(PRThread *thread)
  605. {
  606.     if (thread->flags & _PR_GLOBAL_SCOPE) {
  607.         close(thread->md.cvar_pollsemfd);
  608.         thread->md.cvar_pollsemfd = -1;
  609.         free_poll_sem(&thread->md);
  610.         thread->md.cvar_pollsem = NULL;
  611.     }
  612. }
  613.  
  614. void _MD_SetPriority(_MDThread *thread, PRThreadPriority newPri)
  615. {
  616.     return;
  617. }
  618.  
  619. extern void _MD_unix_terminate_waitpid_daemon(void);
  620.  
  621. void
  622. _MD_CleanupBeforeExit(void)
  623. {
  624.     extern PRInt32    _pr_cpus_exit;
  625.  
  626.     _MD_unix_terminate_waitpid_daemon();
  627.  
  628.     _pr_irix_exit_now = 1;
  629.     if (_pr_numCPU > 1) {
  630.         /*
  631.          * Set a global flag, and wakeup all cpus which will notice the flag
  632.          * and exit.
  633.          */
  634.         _pr_cpus_exit = getpid();
  635.         _MD_Wakeup_CPUs();
  636.         while(_pr_numCPU > 1) {
  637.             _PR_WAIT_SEM(_pr_irix_exit_sem);
  638.             _pr_numCPU--;
  639.         }
  640.     }
  641.     /*
  642.      * cause global threads on the recycle list to exit
  643.      */
  644.      _PR_DEADQ_LOCK;
  645.      if (_PR_NUM_DEADNATIVE != 0) {
  646.     PRThread *thread;
  647.         PRCList *ptr;
  648.  
  649.         ptr = _PR_DEADNATIVEQ.next;
  650.         while( ptr != &_PR_DEADNATIVEQ ) {
  651.             thread = _PR_THREAD_PTR(ptr);
  652.         _MD_CVAR_POST_SEM(thread);
  653.                 ptr = ptr->next;
  654.         } 
  655.      }
  656.      _PR_DEADQ_UNLOCK;
  657.      while(_PR_NUM_DEADNATIVE > 1) {
  658.     _PR_WAIT_SEM(_pr_irix_exit_sem);
  659.     _PR_DEC_DEADNATIVE;
  660.      }
  661. }
  662.  
  663. #ifndef IRIX5_3
  664. extern void __sgi_prda_procmask(int);
  665. #endif
  666.  
  667. PRStatus
  668. _MD_InitThread(PRThread *thread, PRBool wakeup_parent)
  669. {
  670.     struct sigaction sigact;
  671.     PRStatus rv = PR_SUCCESS;
  672.  
  673.     if (thread->flags & _PR_GLOBAL_SCOPE) {
  674.         /*
  675.          * create a polled semaphore
  676.          *
  677.          * NOTE: On Irix there is a bug which requires the sproc that
  678.          *         created a polled semaphore to not exit for that semaphore
  679.          *         to be useable by other sprocs.
  680.          */
  681.         thread->md.id = getpid();
  682.         thread->md.cvar_pollsemfd = -1;
  683.         if (new_poll_sem(&thread->md,0) == PR_FAILURE) {
  684.             if (wakeup_parent == PR_TRUE)
  685.                  unblockproc(getppid());
  686.             rv = PR_FAILURE;
  687.         }
  688.         thread->md.cvar_pollsemfd =
  689.             _PR_OPEN_POLL_SEM(thread->md.cvar_pollsem);
  690.         if ((thread->md.cvar_pollsemfd < 0)) {
  691.             free_poll_sem(&thread->md);
  692.             if (wakeup_parent == PR_TRUE)
  693.                  unblockproc(getppid());
  694.             rv = PR_FAILURE;
  695.         }
  696.         setblockproccnt(thread->md.id, 0);
  697.         _MD_SET_SPROC_PID(getpid());    
  698. #ifndef IRIX5_3
  699.         /*
  700.          * enable user-level processing of sigprocmask(); this is an
  701.          * undocumented feature available in Irix 6.2, 6.3, 6.4 and 6.5
  702.          */
  703.         __sgi_prda_procmask(USER_LEVEL);
  704. #endif
  705.         /*
  706.          * set up SIGUSR1 handler; this is used to save state
  707.          * during PR_SuspendAll
  708.          */
  709.         sigact.sa_handler = save_context_and_block;
  710.         sigact.sa_flags = SA_RESTART;
  711.         /*
  712.          * Must mask clock interrupts
  713.          */
  714.         sigact.sa_mask = timer_set;
  715.         sigaction(SIGUSR1, &sigact, 0);
  716.  
  717.  
  718.         if (_nspr_terminate_on_error) {
  719.             /*
  720.              * PR_SETABORTSIG is a new command implemented in a patch to
  721.              * Irix 6.2, 6.3 and 6.4. This causes a signal to be sent to all
  722.              * sprocs in the process when one of them terminates abnormally
  723.              *
  724.              */
  725.  
  726.             if (prctl(PR_SETABORTSIG, SIGKILL) < 0) {
  727.                 /*
  728.                  *  if (errno == EINVAL)
  729.                  *
  730.                  *    PR_SETABORTSIG not supported under this OS.
  731.                  *    You may want to get a recent kernel rollup patch that
  732.                  *    supports this feature.
  733.                  */
  734.                 /*
  735.                  * SIGCLD handler for detecting abormally-terminating
  736.                  * sprocs
  737.                  */
  738.                 sigact.sa_handler = sigchld_handler;
  739.                 sigact.sa_flags = SA_RESTART;
  740.                 sigact.sa_mask = ints_off;
  741.                 sigaction(SIGCLD, &sigact, NULL);
  742.             }
  743.         }
  744.         /*
  745.          * unblock the parent sproc
  746.          */
  747.         if (wakeup_parent == PR_TRUE)
  748.             unblockproc(getppid());
  749.     }
  750.     return rv;
  751. }
  752.  
  753. PR_EXTERN(void ) _MD_exit(PRIntn status)
  754. {
  755.     /*
  756.      * Cause SIGKILL to be sent to other sprocs, if any, in the application
  757.      */
  758.     prctl(PR_SETEXITSIG, SIGKILL);
  759.     exit(status);
  760. }
  761.  
  762. void
  763. _MD_InitRunningCPU(_PRCPU *cpu)
  764. {
  765.     extern int _pr_md_pipefd[2];
  766.  
  767.     _MD_unix_init_running_cpu(cpu);
  768.     cpu->md.id = getpid();
  769.     _MD_SET_SPROC_PID(getpid());    
  770.     if (_pr_md_pipefd[0] >= 0) {
  771.         _PR_IOQ_MAX_OSFD(cpu) = _pr_md_pipefd[0];
  772.         FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(cpu));
  773.     }
  774. }
  775.  
  776. void
  777. _MD_ExitThread(PRThread *thread)
  778. {
  779.     if (thread->flags & _PR_GLOBAL_SCOPE) {
  780.         _MD_ATOMIC_DECREMENT(&_pr_md_irix_sprocs);
  781.         _MD_CLEAN_THREAD(thread);
  782.         _MD_SET_CURRENT_THREAD(NULL);
  783.     }
  784. }
  785.  
  786. void
  787. _MD_SuspendCPU(_PRCPU *cpu)
  788. {
  789.     PRInt32 rv;
  790.  
  791.     cpu->md.suspending_id = getpid();
  792.     rv = kill(cpu->md.id, SIGUSR1);
  793.     PR_ASSERT(rv == 0);
  794.     /*
  795.      * now, block the current thread/cpu until woken up by the suspended
  796.      * thread from it's SIGUSR1 signal handler
  797.      */
  798.     blockproc(getpid());
  799.  
  800. }
  801.  
  802. void
  803. _MD_ResumeCPU(_PRCPU *cpu)
  804. {
  805.     unblockproc(cpu->md.id);
  806. }
  807.  
  808. #if 0
  809. /*
  810.  * save the register context of a suspended sproc
  811.  */
  812. void get_context(PRThread *thr)
  813. {
  814.     int len, fd;
  815.     char pidstr[24];
  816.     char path[24];
  817.  
  818.     /*
  819.      * open the file corresponding to this process in procfs
  820.      */
  821.     sprintf(path,"/proc/%s","00000");
  822.     len = strlen(path);
  823.     sprintf(pidstr,"%d",thr->md.id);
  824.     len -= strlen(pidstr);
  825.     sprintf(path + len,"%s",pidstr);
  826.     fd = open(path,O_RDONLY);
  827.     if (fd >= 0) {
  828.         (void) ioctl(fd, PIOCGREG, thr->md.gregs);
  829.         close(fd);
  830.     }
  831.     return;
  832. }
  833. #endif    /* 0 */
  834.  
  835. void
  836. _MD_SuspendThread(PRThread *thread)
  837. {
  838.     PRInt32 rv;
  839.  
  840.     PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) &&
  841.         (thread->flags & _PR_GCABLE_THREAD));
  842.  
  843.     thread->md.suspending_id = getpid();
  844.     rv = kill(thread->md.id, SIGUSR1);
  845.     PR_ASSERT(rv == 0);
  846.     /*
  847.      * now, block the current thread/cpu until woken up by the suspended
  848.      * thread from it's SIGUSR1 signal handler
  849.      */
  850.     blockproc(getpid());
  851. }
  852.  
  853. void
  854. _MD_ResumeThread(PRThread *thread)
  855. {
  856.     PRInt32 rv;
  857.  
  858.     PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) &&
  859.         (thread->flags & _PR_GCABLE_THREAD));
  860.     rv = unblockproc(thread->md.id);
  861. }
  862.  
  863. /*
  864.  * return the set of processors available for scheduling procs in the
  865.  * "mask" argument
  866.  */
  867. PRInt32 _MD_GetThreadAffinityMask(PRThread *unused, PRUint32 *mask)
  868. {
  869.     PRInt32 nprocs, rv;
  870.     struct pda_stat *pstat;
  871. #define MAX_PROCESSORS    32
  872.  
  873.     nprocs = sysmp(MP_NPROCS);
  874.     if (nprocs < 0)
  875.         return(-1);
  876.     pstat = PR_MALLOC(sizeof(struct pda_stat) * nprocs);
  877.     if (pstat == NULL)
  878.         return(-1);
  879.     rv = sysmp(MP_STAT, pstat);
  880.     if (rv < 0) {
  881.         PR_DELETE(pstat);
  882.         return(-1);
  883.     }
  884.     /*
  885.      * look at the first 32 cpus
  886.      */
  887.     nprocs = (nprocs > MAX_PROCESSORS) ? MAX_PROCESSORS : nprocs;
  888.     *mask = 0;
  889.     while (nprocs) {
  890.         if ((pstat->p_flags & PDAF_ENABLED) &&
  891.             !(pstat->p_flags & PDAF_ISOLATED)) {
  892.             *mask |= (1 << pstat->p_cpuid);
  893.         }
  894.         nprocs--;
  895.         pstat++;
  896.     }
  897.     return 0;
  898. }
  899.  
  900. static char *_thr_state[] = {
  901.     "UNBORN",
  902.     "RUNNABLE",
  903.     "RUNNING",
  904.     "LOCK_WAIT",
  905.     "COND_WAIT",
  906.     "JOIN_WAIT",
  907.     "IO_WAIT",
  908.     "SUSPENDED",
  909.     "DEAD"
  910. };
  911.  
  912. _PR_List_Threads()
  913. {
  914.     PRThread *thr;
  915.     void *handle;
  916.     struct _PRCPU *cpu;
  917.     PRCList *qp;
  918.     int len, status, rv, fd;
  919.     char pidstr[24];
  920.     char path[24];
  921.     prpsinfo_t pinfo;
  922.  
  923.  
  924.     printf("\n%s %-s\n"," ","LOCAL Threads");
  925.     printf("%s %-s\n"," ","----- -------");
  926.     printf("%s %-14s %-10s %-12s %-3s %-10s %-10s %-12s\n\n"," ",
  927.         "Thread", "State", "Wait-Handle",
  928.         "Cpu","Stk-Base","Stk-Sz","SP");
  929.     for (qp = _PR_ACTIVE_LOCAL_THREADQ().next;
  930.         qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) {
  931.         thr = _PR_ACTIVE_THREAD_PTR(qp);
  932.         printf("%s 0x%-12x %-10s "," ",thr,_thr_state[thr->state]);
  933.         if (thr->state == _PR_LOCK_WAIT)
  934.             handle = thr->wait.lock;
  935.         else if (thr->state == _PR_COND_WAIT)
  936.             handle = thr->wait.cvar;
  937.         else
  938.             handle = NULL;
  939.         if (handle)
  940.             printf("0x%-10x ",handle);
  941.         else
  942.             printf("%-12s "," ");
  943.         printf("%-3d ",thr->cpu->id);
  944.         printf("0x%-8x ",thr->stack->stackBottom);
  945.         printf("0x%-8x ",thr->stack->stackSize);
  946.         printf("0x%-10x\n",thr->md.jb[JB_SP]);
  947.     }
  948.  
  949.     printf("\n%s %-s\n"," ","GLOBAL Threads");
  950.     printf("%s %-s\n"," ","------ -------");
  951.     printf("%s %-14s %-6s %-12s %-12s %-12s %-12s\n\n"," ","Thread",
  952.         "Pid","State","Wait-Handle",
  953.         "Stk-Base","Stk-Sz");
  954.  
  955.     for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next;
  956.         qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) {
  957.         thr = _PR_ACTIVE_THREAD_PTR(qp);
  958.         if (thr->cpu != NULL)
  959.             continue;        /* it is a cpu thread */
  960.         printf("%s 0x%-12x %-6d "," ",thr,thr->md.id);
  961.         /*
  962.          * check if the sproc is still running
  963.          * first call prctl(PR_GETSHMASK,pid) to check if
  964.          * the process is part of the share group (the pid
  965.          * could have been recycled by the OS)
  966.          */
  967.         if (prctl(PR_GETSHMASK,thr->md.id) < 0) {
  968.             printf("%-12s\n","TERMINATED");
  969.             continue;
  970.         }
  971.         /*
  972.          * Now, check if the sproc terminated and is in zombie
  973.          * state
  974.          */
  975.         sprintf(path,"/proc/pinfo/%s","00000");
  976.         len = strlen(path);
  977.         sprintf(pidstr,"%d",thr->md.id);
  978.         len -= strlen(pidstr);
  979.         sprintf(path + len,"%s",pidstr);
  980.         fd = open(path,O_RDONLY);
  981.         if (fd >= 0) {
  982.             if (ioctl(fd, PIOCPSINFO, &pinfo) < 0)
  983.                 printf("%-12s ","TERMINATED");
  984.             else if (pinfo.pr_zomb)
  985.                 printf("%-12s ","TERMINATED");
  986.             else
  987.                 printf("%-12s ",_thr_state[thr->state]);
  988.             close(fd);
  989.         } else {
  990.             printf("%-12s ","TERMINATED");
  991.         }
  992.  
  993.         if (thr->state == _PR_LOCK_WAIT)
  994.             handle = thr->wait.lock;
  995.         else if (thr->state == _PR_COND_WAIT)
  996.             handle = thr->wait.cvar;
  997.         else
  998.             handle = NULL;
  999.         if (handle)
  1000.             printf("%-12x ",handle);
  1001.         else
  1002.             printf("%-12s "," ");
  1003.         printf("0x%-10x ",thr->stack->stackBottom);
  1004.         printf("0x%-10x\n",thr->stack->stackSize);
  1005.     }
  1006.  
  1007.     printf("\n%s %-s\n"," ","CPUs");
  1008.     printf("%s %-s\n"," ","----");
  1009.     printf("%s %-14s %-6s %-12s \n\n"," ","Id","Pid","State");
  1010.  
  1011.  
  1012.     for (qp = _PR_CPUQ().next; qp != &_PR_CPUQ(); qp = qp->next) {
  1013.         cpu = _PR_CPU_PTR(qp);
  1014.         printf("%s %-14d %-6d "," ",cpu->id,cpu->md.id);
  1015.         /*
  1016.          * check if the sproc is still running
  1017.          * first call prctl(PR_GETSHMASK,pid) to check if
  1018.          * the process is part of the share group (the pid
  1019.          * could have been recycled by the OS)
  1020.          */
  1021.         if (prctl(PR_GETSHMASK,cpu->md.id) < 0) {
  1022.             printf("%-12s\n","TERMINATED");
  1023.             continue;
  1024.         }
  1025.         /*
  1026.          * Now, check if the sproc terminated and is in zombie
  1027.          * state
  1028.          */
  1029.         sprintf(path,"/proc/pinfo/%s","00000");
  1030.         len = strlen(path);
  1031.         sprintf(pidstr,"%d",cpu->md.id);
  1032.         len -= strlen(pidstr);
  1033.         sprintf(path + len,"%s",pidstr);
  1034.         fd = open(path,O_RDONLY);
  1035.         if (fd >= 0) {
  1036.             if (ioctl(fd, PIOCPSINFO, &pinfo) < 0)
  1037.                 printf("%-12s\n","TERMINATED");
  1038.             else if (pinfo.pr_zomb)
  1039.                 printf("%-12s\n","TERMINATED");
  1040.             else
  1041.                 printf("%-12s\n","RUNNING");
  1042.             close(fd);
  1043.         } else {
  1044.             printf("%-12s\n","TERMINATED");
  1045.         }
  1046.  
  1047.     }
  1048.     fflush(stdout);
  1049. }
  1050. #endif /* defined(_PR_PTHREADS) */ 
  1051.  
  1052. PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
  1053. {
  1054. #if !defined(_PR_PTHREADS)
  1055.     if (isCurrent) {
  1056.         (void) setjmp(t->md.jb);
  1057.     }
  1058.     *np = sizeof(t->md.jb) / sizeof(PRWord);
  1059.     return (PRWord *) (t->md.jb);
  1060. #else
  1061.     *np = 0;
  1062.     return NULL;
  1063. #endif
  1064. }
  1065.  
  1066. void _MD_EarlyInit(void)
  1067. {
  1068. #if !defined(_PR_PTHREADS)
  1069.     char *eval;
  1070.     int fd;
  1071.  
  1072.     sigemptyset(&ints_off);
  1073.     sigaddset(&ints_off, SIGALRM);
  1074.     sigaddset(&ints_off, SIGIO);
  1075.     sigaddset(&ints_off, SIGCLD);
  1076.  
  1077.     if (eval = getenv("_NSPR_TERMINATE_ON_ERROR"))
  1078.         _nspr_terminate_on_error = (0 == atoi(eval) == 0) ? PR_FALSE : PR_TRUE;
  1079.  
  1080.     fd = open("/dev/zero",O_RDWR , 0);
  1081.     if (fd < 0) {
  1082.         perror("open /dev/zero failed");
  1083.         exit(1);
  1084.     }
  1085.     /*
  1086.      * Set up the sproc private data area.
  1087.      * This region exists at the same address, _nspr_sproc_private, for
  1088.      * every sproc, but each sproc gets a private copy of the region.
  1089.      */
  1090.     _nspr_sproc_private = mmap(0, _pr_pageSize, PROT_READ | PROT_WRITE,
  1091.         MAP_PRIVATE| MAP_LOCAL, fd, 0);
  1092.     if (_nspr_sproc_private == (void*)-1) {
  1093.         perror("mmap /dev/zero failed");
  1094.         exit(1);
  1095.     }
  1096.     close(fd);
  1097. #endif
  1098.     _MD_IntervalInit();
  1099. }  /* _MD_EarlyInit */
  1100.  
  1101. void _MD_IrixInit()
  1102. {
  1103. #if !defined(_PR_PTHREADS)
  1104.     struct sigaction sigact;
  1105.     rlim_t stack_max_limit;
  1106.     PRThread *me = _PR_MD_CURRENT_THREAD();
  1107.  
  1108. #ifndef IRIX5_3
  1109.     /*
  1110.      * enable user-level processing of sigprocmask(); this is an undocumented
  1111.      * feature available in Irix 6.2, 6.3, 6.4 and 6.5
  1112.      */
  1113.     __sgi_prda_procmask(USER_LEVEL);
  1114. #endif
  1115.  
  1116.     /*
  1117.      * set up SIGUSR1 handler; this is used to save state
  1118.      * during PR_SuspendAll
  1119.      */
  1120.     sigact.sa_handler = save_context_and_block;
  1121.     sigact.sa_flags = SA_RESTART;
  1122.     sigact.sa_mask = ints_off;
  1123.     sigaction(SIGUSR1, &sigact, 0);
  1124.  
  1125.     /*
  1126.      * Change the name of the core file from core to core.pid,
  1127.      * This is inherited by the sprocs created by this process
  1128.      */
  1129. #ifndef IRIX5_3
  1130.     prctl(PR_COREPID, 0, 1);
  1131. #endif
  1132.     /*
  1133.      * Irix-specific terminate on error processing
  1134.      */
  1135.     if (_nspr_terminate_on_error) {
  1136.         /*
  1137.          * PR_SETABORTSIG is a new command implemented in a patch to
  1138.          * Irix 6.2, 6.3 and 6.4. This causes a signal to be sent to all
  1139.          * sprocs in the process when one of them terminates abnormally
  1140.          *
  1141.          */
  1142.         if (prctl(PR_SETABORTSIG, SIGKILL) < 0) {
  1143.             /*
  1144.              *  if (errno == EINVAL)
  1145.              *
  1146.              *    PR_SETABORTSIG not supported under this OS.
  1147.              *    You may want to get a recent kernel rollup patch that
  1148.              *    supports this feature.
  1149.               *
  1150.              */
  1151.             /*
  1152.              * PR_SETEXITSIG -  send the SIGCLD signal to the parent
  1153.              *            sproc when any sproc terminates
  1154.              *
  1155.              *    This is used to cause the entire application to
  1156.              *    terminate when    any sproc terminates abnormally by
  1157.              *     receipt of a SIGSEGV, SIGBUS or SIGABRT signal.
  1158.              *    If this is not done, the application may seem
  1159.              *     "hung" to the user because the other sprocs may be
  1160.              *    waiting for resources held by the
  1161.              *    abnormally-terminating sproc.
  1162.              */
  1163.             prctl(PR_SETEXITSIG, 0);
  1164.  
  1165.             sigact.sa_handler = sigchld_handler;
  1166.             sigact.sa_flags = SA_RESTART;
  1167.             sigact.sa_mask = ints_off;
  1168.             sigaction(SIGCLD, &sigact, NULL);
  1169.         }
  1170.     }
  1171.  
  1172.     /*
  1173.      * setup stack fields for the primordial thread
  1174.      */
  1175.     me->stack->stackSize = prctl(PR_GETSTACKSIZE);
  1176.     me->stack->stackBottom = me->stack->stackTop - me->stack->stackSize;
  1177. #endif /* _PR_PTHREADS */
  1178.  
  1179.     _PR_UnixInit();
  1180. }
  1181.  
  1182. /**************************************************************************/
  1183. /************** code and such for NSPR 2.0's interval times ***************/
  1184. /**************************************************************************/
  1185.  
  1186. #define PR_CLOCK_GRANULARITY 10000UL
  1187.  
  1188. #ifndef SGI_CYCLECNTR_SIZE
  1189. #define SGI_CYCLECNTR_SIZE      165     /* Size user needs to use to read CC */
  1190. #endif
  1191.  
  1192. static PRUintn mmem_fd = -1;
  1193. static PRIntn clock_width = 0;
  1194. static void *iotimer_addr = NULL;
  1195. static PRUint32 pr_clock_mask = 0;
  1196. static PRUint32 pr_clock_shift = 0;
  1197. static PRIntervalTime pr_ticks = 0;
  1198. static PRUint32 pr_clock_granularity = 1;
  1199. static PRUint32 pr_previous = 0, pr_residual = 0;
  1200.  
  1201. extern PRIntervalTime _PR_UNIX_GetInterval(void);
  1202. extern PRIntervalTime _PR_UNIX_TicksPerSecond(void);
  1203.  
  1204. void _MD_IntervalInit(void)
  1205. {
  1206.     /*
  1207.      * As much as I would like, the service available through this
  1208.      * interface on R3000's (aka, IP12) just isn't going to make it.
  1209.      * The register is only 24 bits wide, and rolls over at a verocious
  1210.      * rate.
  1211.      */
  1212.     PRUint32 one_tick = 0;
  1213.     struct utsname utsinfo;
  1214.     uname(&utsinfo);
  1215.     if ((strncmp("IP12", utsinfo.machine, 4) != 0)
  1216.         && ((mmem_fd = open("/dev/mmem", O_RDONLY)) != -1))
  1217.     {
  1218.         int poffmask = getpagesize() - 1;
  1219.         __psunsigned_t phys_addr, raddr, cycleval;
  1220.  
  1221.         phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval);
  1222.         raddr = phys_addr & ~poffmask;
  1223.         iotimer_addr = mmap(
  1224.             0, poffmask, PROT_READ, MAP_PRIVATE, mmem_fd, (__psint_t)raddr);
  1225.  
  1226.         clock_width = syssgi(SGI_CYCLECNTR_SIZE);
  1227.         if (clock_width < 0)
  1228.         {
  1229.             /* 
  1230.              * We must be executing on a 6.0 or earlier system, since the
  1231.              * SGI_CYCLECNTR_SIZE call is not supported.
  1232.              * 
  1233.              * The only pre-6.1 platforms with 64-bit counters are
  1234.              * IP19 and IP21 (Challenge, PowerChallenge, Onyx).
  1235.              */
  1236.             if (!strncmp(utsinfo.machine, "IP19", 4) ||
  1237.                 !strncmp(utsinfo.machine, "IP21", 4))
  1238.                 clock_width = 64;
  1239.             else
  1240.                 clock_width = 32;
  1241.         }
  1242.  
  1243.         /*
  1244.          * 'cycleval' is picoseconds / increment of the counter.
  1245.          * I'm pushing for a tick to be 100 microseconds, 10^(-4).
  1246.          * That leaves 10^(-8) left over, or 10^8 / cycleval.
  1247.          * Did I do that right?
  1248.          */
  1249.  
  1250.         one_tick =  100000000UL / cycleval ;  /* 100 microseconds */
  1251.  
  1252.         while (0 != one_tick)
  1253.         {
  1254.             pr_clock_shift += 1;
  1255.             one_tick = one_tick >> 1;
  1256.             pr_clock_granularity = pr_clock_granularity << 1;
  1257.         }
  1258.         pr_clock_mask = pr_clock_granularity - 1;  /* to make a mask out of it */
  1259.             
  1260.         iotimer_addr = (void*)
  1261.             ((__psunsigned_t)iotimer_addr + (phys_addr & poffmask));
  1262.     }
  1263.  
  1264. }  /* _PR_MD_INTERVAL_INIT */
  1265.  
  1266. PRIntervalTime _MD_IntervalPerSec()
  1267. {
  1268.     return pr_clock_granularity;
  1269. }
  1270.  
  1271. PRIntervalTime _MD_GetInterval()
  1272. {
  1273.     if (mmem_fd != -1)
  1274.     {
  1275.         if (64 == clock_width)
  1276.         {
  1277.             PRUint64 temp = *(PRUint64*)iotimer_addr;
  1278.             pr_ticks = (PRIntervalTime)(temp >> pr_clock_shift);
  1279.         }
  1280.         else
  1281.         {
  1282.             PRIntervalTime ticks = pr_ticks;
  1283.             PRUint32 now = *(PRUint32*)iotimer_addr, temp;
  1284.             PRUint32 residual = pr_residual, previous = pr_previous;
  1285.  
  1286.             temp = now - previous + residual;
  1287.             residual = temp & pr_clock_mask;
  1288.             ticks += temp >> pr_clock_shift;
  1289.  
  1290.             pr_previous = now;
  1291.             pr_residual = residual;
  1292.             pr_ticks = ticks;
  1293.         }
  1294.     }
  1295.     else
  1296.     {
  1297.         /*
  1298.          * No fast access. Use the time of day clock. This isn't the
  1299.          * right answer since this clock can get set back, tick at odd
  1300.          * rates, and it's expensive to acqurie.
  1301.          */
  1302.         pr_ticks = _PR_UNIX_GetInterval();
  1303.         PR_ASSERT(PR_CLOCK_GRANULARITY > _PR_UNIX_TicksPerSecond());
  1304.         pr_ticks *= (PR_CLOCK_GRANULARITY / _PR_UNIX_TicksPerSecond());
  1305.     }
  1306.     return pr_ticks;
  1307. }  /* _MD_GetInterval */
  1308.  
  1309.