home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / md / mac / macthr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  9.6 KB  |  382 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 <Types.h>
  22. #include <Timer.h>
  23. #include <OSUtils.h>
  24.  
  25. #include <LowMem.h>
  26.  
  27. // This should be in LowMem.h
  28. #ifndef LMSetStackLowPoint
  29. #define LMSetStackLowPoint(value)        \
  30.     *((UInt32 *)(0x110)) = (value)
  31. #endif
  32.  
  33. PRThread *gPrimaryThread = NULL;
  34.  
  35. PR_IMPLEMENT(PRThread *) PR_GetPrimaryThread()
  36. {
  37.     return gPrimaryThread;
  38. }
  39.  
  40. //##############################################################################
  41. //##############################################################################
  42. #pragma mark -
  43. #pragma mark CREATING MACINTOSH THREAD STACKS
  44.  
  45.  
  46. /*
  47. **    Allocate a new memory segment.  We allocate it from our figment heap.  Currently,
  48. **    it is being used for per thread stack space.
  49. **    
  50. **    Return the segment's access rights and size.  vaddr is used on Unix platforms to
  51. **    map an existing address for the segment.
  52. */
  53. PRStatus _MD_AllocSegment(PRSegment *seg, PRUint32 size, void *vaddr)
  54. {
  55.     PR_ASSERT(seg != 0);
  56.     PR_ASSERT(size != 0);
  57.     PR_ASSERT(vaddr == 0);
  58.  
  59.     /*    
  60.     ** Take the actual memory for the segment out of our Figment heap.
  61.     */
  62.  
  63.     seg->vaddr = (char *)malloc(size);
  64.  
  65.     if (seg->vaddr == NULL) {
  66.  
  67. #if DEBUG
  68.         DebugStr("\p_MD_AllocSegment failed.");
  69. #endif
  70.  
  71.         return PR_FAILURE;
  72.     }
  73.  
  74.     seg->access = PR_SEGMENT_RDWR;    
  75.     seg->size = size;    
  76.  
  77.     return PR_SUCCESS;
  78. }
  79.  
  80.  
  81. /*
  82. **    Free previously allocated memory segment.
  83. */
  84. void _MD_FreeSegment(PRSegment *seg)
  85. {
  86.     PR_ASSERT((seg->flags & _PR_SEG_VM) == 0);
  87.  
  88.     if (seg->vaddr != NULL)
  89.         DisposePtr((Ptr)(seg->vaddr));
  90. }
  91.  
  92.  
  93. /*
  94. **    The thread's stack has been allocated and its fields are already properly filled
  95. **    in by PR.  Perform any debugging related initialization here.
  96. **
  97. **    Put a recognizable pattern so that we can find it from Macsbug.
  98. **    Put a cookie at the top of the stack so that we can find it from Macsbug.
  99. */
  100. void _MD_InitStack(PRThreadStack *ts, int redZoneBytes)
  101.     {
  102. #pragma unused (redZoneBytes)
  103. #if DEVELOPER_DEBUG
  104.     //    Put a cookie at the top of the stack so that we can find 
  105.     //    it from Macsbug.
  106.     
  107.     memset(ts->allocBase, 0xDC, ts->stackSize);
  108.     
  109.     ((UInt32 *)ts->stackTop)[-1] = 0xBEEFCAFE;
  110.     ((UInt32 *)ts->stackTop)[-2] = (UInt32)gPrimaryThread;
  111.     ((UInt32 *)ts->stackTop)[-3] = (UInt32)(ts);
  112.     ((UInt32 *)ts->stackBottom)[0] = 0xCAFEBEEF;
  113. #else
  114. #pragma unused (ts)
  115. #endif
  116.     
  117.     /*
  118.     **    Turn off the snack stiffer.  The NSPR stacks are allocated in the 
  119.     **    application's heap; this throws the stack sniffer for a tizzy.
  120.     **    Note that the sniffer does not run on machines running the thread manager.
  121.     **    Yes, we will blast the low-mem every time a new stack is created.  We can afford
  122.     **    a couple extra cycles.
  123.     */
  124.     LMSetStackLowPoint(0);
  125.     }
  126.  
  127. extern void _MD_ClearStack(PRThreadStack *ts)
  128.     {
  129. #if DEVELOPER_DEBUG
  130.     //    Clear out our cookies. 
  131.     
  132.     memset(ts->allocBase, 0xEF, ts->allocSize);
  133.     ((UInt32 *)ts->stackTop)[-1] = 0;
  134.     ((UInt32 *)ts->stackTop)[-2] = 0;
  135.     ((UInt32 *)ts->stackTop)[-3] = 0;
  136.     ((UInt32 *)ts->stackBottom)[0] = 0;
  137. #else
  138. #pragma unused (ts)
  139. #endif
  140.     }
  141.  
  142.  
  143. //##############################################################################
  144. //##############################################################################
  145. #pragma mark -
  146. #pragma mark TIME MANAGER-BASED CLOCK
  147.  
  148. TMTask        gTimeManagerTaskElem;
  149.  
  150. extern void _MD_IOInterrupt(void);
  151. _PRInterruptTable _pr_interruptTable[] = {
  152.     { "clock", _PR_MISSED_CLOCK, _PR_ClockInterrupt, },
  153.     { "i/o", _PR_MISSED_IO, _MD_IOInterrupt, },
  154.     { 0 }
  155. };
  156.  
  157. pascal void TimerCallback(TMTaskPtr tmTaskPtr)
  158. {
  159.     _PRCPU *cpu = _PR_MD_CURRENT_CPU();
  160.  
  161.     if (_PR_MD_GET_INTSOFF()) {
  162.         cpu->u.missed[cpu->where] |= _PR_MISSED_CLOCK;
  163.         PrimeTime((QElemPtr)tmTaskPtr, kMacTimerInMiliSecs);
  164.         return;
  165.     }
  166.     _PR_SET_INTSOFF(1);
  167.  
  168.     //    And tell nspr that a clock interrupt occured.
  169.     _PR_ClockInterrupt();
  170.     
  171.     if ((_PR_RUNQREADYMASK(cpu)) >> ((_PR_MD_CURRENT_THREAD()->priority)))
  172.         _PR_SET_RESCHED_FLAG();
  173.     
  174.     _PR_SET_INTSOFF(0);
  175.  
  176.     //    Reset the clock timer so that we fire again.
  177.     PrimeTime((QElemPtr)tmTaskPtr, kMacTimerInMiliSecs);
  178. }
  179.  
  180. #if GENERATINGCFM
  181.  
  182. RoutineDescriptor     gTimerCallbackRD = BUILD_ROUTINE_DESCRIPTOR(uppTimerProcInfo, &TimerCallback);
  183.  
  184. #else
  185.  
  186. asm void gTimerCallbackRD(void)
  187. {
  188.     //    Check out LocalA5.  If it is zero, then
  189.     //    it is our first time through, and we should
  190.     //    store away our A5.  If not, then we are
  191.     //    a real time manager callback, so we should
  192.     //    store away A5, set up our local a5, jsr
  193.     //    to our callback, and then restore the
  194.     //    previous A5.
  195.     
  196.     lea            LocalA5, a0
  197.     move.l        (a0), d0
  198.     cmpi.l        #0, d0
  199.     bne            TimerProc
  200.     
  201.     move.l        a5, (a0)
  202.     rts
  203.  
  204. TimerProc:
  205.     
  206.     //    Save A5, restore our local A5
  207.     
  208.     move.l        a5, -(sp)
  209.     move.l        d0, a5 
  210.     
  211.     //    Jump to our C routine
  212.     
  213.     move.l         a1, -(sp)
  214.     jsr         TimerCallback
  215.     
  216.     //    Restore the previous A5
  217.     
  218.     move.l        (sp)+, a5
  219.  
  220.     rts
  221.  
  222. LocalA5:
  223.  
  224.     dc.l        0
  225.     
  226. }
  227.  
  228. #endif
  229.  
  230. void _MD_StartInterrupts(void)
  231. {
  232.     gPrimaryThread = _PR_MD_CURRENT_THREAD();
  233.  
  234.     //    If we are not generating CFM-happy code, then make sure that 
  235.     //    we call our callback wrapper once so that we can
  236.     //    save away our A5.
  237.  
  238. #if !GENERATINGCFM
  239.     gTimerCallbackRD();
  240. #endif
  241.  
  242.     //    Fill in the Time Manager queue element
  243.     
  244.     gTimeManagerTaskElem.tmAddr = (TimerUPP)&gTimerCallbackRD;
  245.     gTimeManagerTaskElem.tmCount = 0;
  246.     gTimeManagerTaskElem.tmWakeUp = 0;
  247.     gTimeManagerTaskElem.tmReserved = 0;
  248.  
  249.     //    Make sure that our time manager task is ready to go.
  250.     InsTime((QElemPtr)&gTimeManagerTaskElem);
  251.     
  252.     PrimeTime((QElemPtr)&gTimeManagerTaskElem, kMacTimerInMiliSecs);
  253. }
  254.  
  255. void _MD_StopInterrupts(void)
  256. {
  257.     if (gTimeManagerTaskElem.tmAddr != NULL) {
  258.         RmvTime((QElemPtr)&gTimeManagerTaskElem);
  259.         gTimeManagerTaskElem.tmAddr = NULL;
  260.     }
  261. }
  262.  
  263. void _MD_PauseCPU(PRIntervalTime timeout)
  264. {
  265. #pragma unused (timeout)
  266.  
  267.     unsigned long finalTicks;
  268.     
  269.     if (timeout != PR_INTERVAL_NO_WAIT) {
  270.         Delay(1,&finalTicks);
  271.         (void) _MD_IOInterrupt();
  272.     }
  273. }
  274.  
  275.  
  276. //##############################################################################
  277. //##############################################################################
  278. #pragma mark -
  279. #pragma mark THREAD SUPPORT FUNCTIONS
  280.  
  281. #include <OpenTransport.h> /* for error codes */
  282.  
  283. PRStatus _MD_InitThread(PRThread *thread)
  284. {
  285.     thread->md.asyncIOLock = PR_NewLock();
  286.     PR_ASSERT(thread->md.asyncIOLock != NULL);
  287.     thread->md.asyncIOCVar = PR_NewCondVar(thread->md.asyncIOLock);
  288.     PR_ASSERT(thread->md.asyncIOCVar != NULL);
  289.  
  290.     if (thread->md.asyncIOLock == NULL || thread->md.asyncIOCVar == NULL)
  291.         return PR_FAILURE;
  292.     else
  293.         return PR_SUCCESS;
  294. }
  295.  
  296. PRStatus _MD_wait(PRThread *thread, PRIntervalTime timeout)
  297. {
  298. #pragma unused (timeout)
  299.  
  300.     _MD_SWITCH_CONTEXT(thread);
  301.     return PR_SUCCESS;
  302. }
  303.  
  304. void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout)
  305. {
  306.     intn is;
  307.     PRIntervalTime timein = PR_IntervalNow();
  308.     PRStatus status = PR_SUCCESS;
  309.  
  310.     _PR_INTSOFF(is);
  311.     PR_Lock(thread->md.asyncIOLock);
  312.     if (timeout == PR_INTERVAL_NO_TIMEOUT) {
  313.         while ((thread->io_pending) && (status == PR_SUCCESS))
  314.             status = PR_WaitCondVar(thread->md.asyncIOCVar, PR_INTERVAL_NO_TIMEOUT);
  315.     } else {
  316.         while ((thread->io_pending) && ((PRIntervalTime)(PR_IntervalNow() - timein) < timeout))
  317.             status = PR_WaitCondVar(thread->md.asyncIOCVar, timeout);
  318.     }
  319.     if ((status == PR_FAILURE) && (PR_GetError() == PR_PENDING_INTERRUPT_ERROR)) {
  320.         thread->md.osErrCode = kEINTRErr;
  321.     } else if (thread->io_pending) {
  322.         thread->md.osErrCode = kETIMEDOUTErr;
  323.         PR_SetError(PR_IO_TIMEOUT_ERROR, kETIMEDOUTErr);
  324.     }
  325.     PR_Unlock(thread->md.asyncIOLock);
  326.     _PR_FAST_INTSON(is);
  327. }
  328.  
  329. void DoneWaitingOnThisThread(PRThread *thread)
  330. {
  331.     intn is;
  332.  
  333.     _PR_INTSOFF(is);
  334.     PR_Lock(thread->md.asyncIOLock);
  335.     thread->io_pending = PR_FALSE;
  336.     /* let the waiting thread know that async IO completed */
  337.     PR_NotifyCondVar(thread->md.asyncIOCVar);
  338.     PR_Unlock(thread->md.asyncIOLock);
  339.     _PR_FAST_INTSON(is);
  340. }
  341.  
  342. //##############################################################################
  343. //##############################################################################
  344. #pragma mark -
  345. #pragma mark PROCESS SUPPORT FUNCTIONS
  346.  
  347. PRProcess * _MD_CreateProcess(
  348.     const char *path,
  349.     char *const *argv,
  350.     char *const *envp,
  351.     const PRProcessAttr *attr)
  352. {
  353. #pragma unused (path, argv, envp, attr)
  354.  
  355.     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr);
  356.     return NULL;
  357. }
  358.  
  359. PRStatus _MD_DetachProcess(PRProcess *process)
  360. {
  361. #pragma unused (process)
  362.  
  363.     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr);
  364.     return PR_FAILURE;
  365. }
  366.  
  367. PRStatus _MD_WaitProcess(PRProcess *process, PRInt32 *exitCode)
  368. {
  369. #pragma unused (process, exitCode)
  370.  
  371.     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr);
  372.     return PR_FAILURE;
  373. }
  374.  
  375. PRStatus _MD_KillProcess(PRProcess *process)
  376. {
  377. #pragma unused (process)
  378.  
  379.     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr);
  380.     return PR_FAILURE;
  381. }
  382.