home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / md / windows / w16thred.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  13.8 KB  |  408 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. #include <sys/timeb.h>
  21. #include <stdio.h>
  22.  
  23. /*
  24. ** DispatchTrace -- define a thread dispatch trace entry
  25. **
  26. ** The DispatchTrace oject(s) are instantiated in a single
  27. ** array. Think of the array as a push-down stack; entry
  28. ** zero is the most recent, entry one the next most recent, etc.
  29. ** For each time PR_MD_RESTORE_CONTEXT() is called, the array
  30. ** is Pushed down and entry zero is overwritten with data
  31. ** for the newly dispatched thread.
  32. **
  33. ** Function TraceDispatch() manages the DispatchTrace array.
  34. **
  35. */
  36. typedef struct DispatchTrace
  37. {
  38.     PRThread *          thread;
  39.     PRUint32            state;
  40.     PRInt16             mdThreadNumber;
  41.     PRInt16             unused;
  42.     PRThreadPriority    priority;
  43.     
  44. } DispatchTrace, *DispatchTracePtr ;
  45.  
  46. static void TraceDispatch( PRThread *thread );
  47.  
  48.  
  49. PRThread                *_pr_primordialThread;
  50.  
  51. /*
  52. ** Note: the static variables must be on the data-segment because
  53. ** the stack is destroyed during shadow-stack copy operations.
  54. **
  55. */
  56. static char * pSource;          /* ptr to sourc of a "shadow-stack" copy */
  57. static char * pTarget;          /* ptr to target of a "shadow-stack" copy */
  58. static int   cxByteCount;       /* number of bytes for "shadow-stack" copy */
  59. static int   bytesMoved;        /* instrumentation: WRT "shadow-stack" copy */
  60. static FILE *    file1 = 0;     /* instrumentation: WRT debug */
  61.  
  62. #define NUM_DISPATCHTRACE_OBJECTS  24
  63. static DispatchTrace dt[NUM_DISPATCHTRACE_OBJECTS] = {0}; /* instrumentation: WRT dispatch */
  64. static PRUint32 dispatchCount = 0;  /* instrumentation: number of thread dispatches */
  65.  
  66. static int OldPriorityOfPrimaryThread   = -1;
  67. static int TimeSlicesOnNonPrimaryThread =  0;
  68. static PRUint32 threadNumber = 1;   /* Instrumentation: monotonically increasing number */
  69.  
  70.  
  71.  
  72. /*
  73. ** _PR_MD_FINAL_INIT() -- Final MD Initialization
  74. **
  75. ** Poultry Problems! ... The stack, as allocated by PR_NewStack()
  76. ** is called from here, late in initialization, because PR_NewStack()
  77. ** requires lots of things working. When some elements of the
  78. ** primordial thread are created, early in initialization, the
  79. ** shadow stack is not one of these things. The "shadow stack" is
  80. ** created here, late in initiailization using PR_NewStack(), to
  81. ** ensure consistency in creation of the related objects.
  82. ** 
  83. ** A new ThreadStack, and all its affiliated structures, is allocated
  84. ** via the call to PR_NewStack(). The PRThread structure in the
  85. ** new stack is ignored; the old PRThread structure is used (why?).
  86. ** The old PRThreadStack structure is abandoned.
  87. **
  88. */
  89. void
  90. _PR_MD_FINAL_INIT()
  91. {
  92.     PRThreadStack *     stack = 0;
  93.     PRInt32             stacksize = 0;
  94.     PRThread *          me = _PR_MD_CURRENT_THREAD();
  95.     
  96.     _PR_ADJUST_STACKSIZE( stacksize );
  97.     stack = _PR_NewStack( stacksize );
  98.     
  99.     me->stack = stack;
  100.     stack->thr = me;
  101.     
  102.     return;
  103. } /* --- end _PR_MD_FINAL_INIT() --- */
  104.  
  105.  
  106. void
  107. _MD_INIT_RUNNING_CPU( struct _PRCPU *cpu )
  108. {
  109.     PR_INIT_CLIST(&(cpu->md.ioQ));
  110.     cpu->md.ioq_max_osfd = -1;
  111.     cpu->md.ioq_timeout = PR_INTERVAL_NO_TIMEOUT;
  112. }    
  113.  
  114.  
  115. void
  116. _PR_MD_YIELD( void )
  117. {
  118.     PR_ASSERT(0);
  119. }
  120.  
  121. /*
  122. ** _PR_MD_INIT_STACK() -- Win16 specific Stack initialization.
  123. **
  124. **
  125. */
  126.  
  127. void
  128. _PR_MD_INIT_STACK( PRThreadStack *ts, PRIntn redzone )
  129. {
  130.     ts->md.stackTop = ts->stackTop - sizeof(PRThread);
  131.     ts->md.cxByteCount = 0;
  132.     
  133.     return;
  134. } /* --- end _PR_MD_INIT_STACK() --- */
  135.  
  136. /*
  137. **  _PR_MD_INIT_THREAD() -- Win16 specific Thread initialization.
  138. **
  139. */
  140. PRStatus
  141. _PR_MD_INIT_THREAD(PRThread *thread)
  142. {
  143.     if ( thread->flags & _PR_PRIMORDIAL)
  144.     {
  145.         _pr_primordialThread = thread;
  146.         thread->md.threadNumber = 1;
  147.     }
  148.     else
  149.     {
  150.         thread->md.threadNumber = ++threadNumber;
  151.     }
  152.  
  153.     thread->md.magic = _MD_MAGIC_THREAD;
  154.     strcpy( thread->md.guardBand, "GuardBand" );
  155.     
  156.     return PR_SUCCESS;
  157. }
  158.  
  159.  
  160. PRStatus
  161. _PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
  162. {
  163.     _MD_SWITCH_CONTEXT( thread );
  164.     
  165.     return( PR_SUCCESS );
  166. }
  167.  
  168. void *PR_W16GetExceptionContext(void)
  169. {
  170.     return _MD_CURRENT_THREAD()->md.exceptionContext;
  171. }
  172.  
  173. void
  174. PR_W16SetExceptionContext(void *context)
  175. {
  176.     _MD_CURRENT_THREAD()->md.exceptionContext = context;
  177. }
  178.  
  179.  
  180.  
  181.  
  182. /*
  183. ** _MD_RESTORE_CONTEXT() -- Resume execution of thread 't'.
  184. **
  185. ** Win16 threading is based on the NSPR 2.0 general model of
  186. ** user threads. It differs from the general model in that a 
  187. ** single "real" stack segment is used for execution of all 
  188. ** threads. The context of the suspended threads is preserved
  189. ** in the md.context [and related members] of the PRThread 
  190. ** structure. The stack context of the suspended thread is
  191. ** preserved in a "shadow stack" object.
  192. **
  193. ** _MD_RESTORE_CONTEXT() implements most of the thread switching
  194. ** for NSPR's implementation of Win16 theads.
  195. **
  196. ** Operations Notes:
  197. **
  198. ** Function PR_NewStack() in prustack.c allocates a new
  199. ** PRThreadStack, PRStack, PRSegment, and a "shadow" stack
  200. ** for a thread. These structures are wired together to
  201. ** form the basis of Win16 threads. The thread and shadow
  202. ** stack structures are created as part of PR_CreateThread().
  203. ** 
  204. ** Note! Some special "magic" is applied to the "primordial"
  205. ** thread. The physical layout of the PRThread, PRThreadStack,
  206. ** shadow stack, ... is somewhat different. Watch yourself when
  207. ** mucking around with it. ... See _PR_MD_FINAL_INIT() for most
  208. ** of the special treatment of the primordial thread.
  209. **
  210. ** Function _PR_MD_INIT_STACK() initializes the value of
  211. ** PRThreadStack member md.cxByteCount to zero; there
  212. ** is no context to be restored for a thread's initial
  213. ** dispatch. The value of member md.stackTop is set to
  214. ** point to the highest usable address on the shadow stack.
  215. ** This point corresponds to _pr_top_of_task_stack on the
  216. ** system's operating stack.
  217. **
  218. ** _pr_top_of_task_stack points to a place on the system stack
  219. ** considered to be "close to the top". Stack context is preserved
  220. ** relative to this point.
  221. **
  222. ** Reminder: In x86 architecture, the stack grows "down".
  223. ** That is: the stack pointer (SP register) is decremented
  224. ** to push objects onto the stack or when a call is made.
  225. ** 
  226. ** Function _PR_MD_WAIT() invokes macro _MD_SWITCH_CONTEXT();
  227. ** this causes the hardware registers to be preserved in a
  228. ** CATCHBUF structure using function Catch() [see _win16.h], 
  229. ** then calls PR_Schedule() to select a new thread for dispatch. 
  230. ** PR_Schedule() calls _MD_RESTORE_CONTEXT() to cause the thread 
  231. ** being suspended's stack to be preserved, to restore the 
  232. ** stack of the to-be-dispactched thread, and to restore the 
  233. ** to-be-dispactched thread's hardware registers.
  234. **
  235. ** At the moment _PR_MD_RESTORE_CONTEXT() is called, the stack
  236. ** pointer (SP) is less than the reference pointer
  237. ** _pr_top_of_task_stack. The distance difference between the SP and
  238. ** _pr_top_of_task_stack is the amount of stack that must be preserved.
  239. ** This value, cxByteCount, is calculated then preserved in the
  240. ** PRThreadStack.md.cxByteCount for later use (size of stack
  241. ** context to restore) when this thread is dispatched again.
  242. ** 
  243. ** A C language for() loop is used to copy, byte-by-byte, the
  244. ** stack data being preserved starting at the "address of t"
  245. ** [Note: 't' is the argument passed to _PR_MD_RESTORE_CONTEXT()]
  246. ** for the length of cxByteCount.
  247. **
  248. ** variables pSource and pTarget are the calculated source and
  249. ** destination pointers for the stack copy operation. These
  250. ** variables are static scope because they cannot be instantiated
  251. ** on the stack itself, since the stack is clobbered by restoring
  252. ** the to-be-dispatched thread's stack context.
  253. **
  254. ** After preserving the suspended thread's stack and architectural
  255. ** context, the to-be-dispatched thread's stack context is copied
  256. ** from its shadow stack to the system operational stack. The copy
  257. ** is done in a small fragment of in-line assembly language. Note:
  258. ** In NSPR 1.0, a while() loop was used to do the copy; when compiled
  259. ** with the MS C 1.52c compiler, the short while loop used no
  260. ** stack variables. The Watcom compiler, specified for use on NSPR 2.0,
  261. ** uses stack variables to implement the same while loop. This is
  262. ** a no-no! The copy operation clobbers these variables making the
  263. ** results of the copy ... unpredictable ... So, a short piece of
  264. ** inline assembly language is used to effect the copy.
  265. **
  266. ** Following the restoration of the to-be-dispatched thread's
  267. ** stack context, another short inline piece of assemble language
  268. ** is used to set the SP register to correspond to what it was
  269. ** when the to-be-dispatched thread was suspended. This value
  270. ** uses the thread's stack->md.cxByteCount as a negative offset 
  271. ** from _pr_top_of_task_stack as the new value of SP.
  272. **
  273. ** Finally, Function Throw() is called to restore the architectural
  274. ** context of the to-be-dispatched thread.
  275. **
  276. ** At this point, the newly dispatched thread appears to resume
  277. ** execution following the _PR_MD_SWITCH_CONTEXT() macro.
  278. **
  279. ** OK, this ain't rocket-science, but it can confuse you easily.
  280. ** If you have to work on this stuff, please take the time to
  281. ** draw, on paper, the structures (PRThread, PRThreadStack,
  282. ** PRSegment, the "shadow stack", the system stack and the related
  283. ** global variables). Hand step it thru the debugger to make sure
  284. ** you understand it very well before making any changes. ...
  285. ** YMMV.
  286. ** 
  287. */
  288. void _MD_RESTORE_CONTEXT(PRThread *t)
  289. {
  290.     dispatchCount++;
  291.     TraceDispatch( t );
  292.     /*    
  293.     **    This is a good opportunity to make sure that the main
  294.     **    mozilla thread actually gets some time.  If interrupts
  295.     **    are on, then we know it is safe to check if the main
  296.     **    thread is being starved.  If moz has not been scheduled
  297.     **    for a long time, then then temporarily bump the fe priority 
  298.     **    up so that it gets to run at least one. 
  299.     */    
  300. // #if 0 // lth. condition off for debug.
  301.     if (_pr_primordialThread == t) {
  302.         if (OldPriorityOfPrimaryThread != -1) {
  303.             PR_SetThreadPriority(_pr_primordialThread, OldPriorityOfPrimaryThread);
  304.             OldPriorityOfPrimaryThread = -1;
  305.         }
  306.         TimeSlicesOnNonPrimaryThread = 0;
  307.     } else {
  308.         TimeSlicesOnNonPrimaryThread++;
  309.     }
  310.  
  311.     if ((TimeSlicesOnNonPrimaryThread >= 20) && (OldPriorityOfPrimaryThread == -1)) {
  312.         OldPriorityOfPrimaryThread = PR_GetThreadPriority(_pr_primordialThread);
  313.         PR_SetThreadPriority(_pr_primordialThread, 31);
  314.         TimeSlicesOnNonPrimaryThread = 0;
  315.     }
  316. // #endif
  317.     /*
  318.     ** Save the Task Stack into the "shadow stack" of the current thread
  319.     */
  320.     cxByteCount  = (int) ((PRUint32) _pr_top_of_task_stack - (PRUint32) &t );
  321.     pSource      = (char *) &t;
  322.     pTarget      = (char *)((PRUint32)_pr_currentThread->stack->md.stackTop 
  323.                             - (PRUint32)cxByteCount );
  324.     _pr_currentThread->stack->md.cxByteCount = cxByteCount;
  325.     
  326.     for( bytesMoved = 0; bytesMoved < cxByteCount; bytesMoved++ )
  327.         *(pTarget + bytesMoved ) = *(pSource + bytesMoved );
  328.     
  329.     /* Mark the new thread as the current thread */
  330.     _pr_currentThread = t;
  331.  
  332.     /*
  333.     ** Now copy the "shadow stack" of the new thread into the Task Stack
  334.     **
  335.     ** REMEMBER:
  336.     **    After the stack has been copied, ALL local variables in this function
  337.     **    are invalid !!
  338.     */
  339.     cxByteCount  = t->stack->md.cxByteCount;
  340.     pSource      = t->stack->md.stackTop - cxByteCount;
  341.     pTarget      = _pr_top_of_task_stack - cxByteCount;
  342.     
  343.     errno = (_pr_currentThread)->md.errcode;
  344.     
  345.     __asm 
  346.     {
  347.         mov cx, cxByteCount
  348.         mov si, WORD PTR [pSource]
  349.         mov di, WORD PTR [pTarget]
  350.         mov ax, WORD PTR [pTarget + 2]
  351.         mov es, ax
  352.         mov ax, WORD PTR [pSource + 2]
  353.         mov bx, ds
  354.         mov ds, ax
  355.         rep movsb
  356.         mov ds, bx
  357.     }
  358.  
  359.     /* 
  360.     ** IMPORTANT:
  361.     ** ----------
  362.     ** SS:SP is now invalid :-( This means that all local variables and
  363.     ** function arguments are invalid and NO function calls can be
  364.     ** made !!! We must fix up SS:SP so that function calls can safely
  365.     ** be made...
  366.     */
  367.  
  368.     __asm {
  369.         mov     ax, WORD PTR [_pr_top_of_task_stack]
  370.         sub     ax, cxByteCount
  371.         mov     sp, ax
  372.     };
  373.  
  374.     /*
  375.     ** Resume execution of thread: t by restoring the thread's context.
  376.     **
  377.     */
  378.     Throw((_pr_currentThread)->md.context, 1);
  379. } /* --- end MD_RESTORE_CONTEXT() --- */
  380.  
  381.  
  382. static void TraceDispatch( PRThread *thread )
  383. {
  384.     int i;
  385.     
  386.     /*
  387.     ** push all DispatchTrace objects to down one slot.
  388.     ** Note: the last entry is lost; last-1 becomes last, etc.
  389.     */
  390.     for( i = NUM_DISPATCHTRACE_OBJECTS -2; i >= 0; i-- )
  391.     {
  392.         dt[i +1] = dt[i];
  393.     }
  394.     
  395.     /*
  396.     ** Build dt[0] from t
  397.     */
  398.     dt->thread = thread;
  399.     dt->state = thread->state;
  400.     dt->mdThreadNumber = thread->md.threadNumber;
  401.     dt->priority = thread->priority;
  402.     
  403.     return;
  404. } /* --- end TraceDispatch() --- */
  405.  
  406.  
  407. /* $$ end W16thred.c */
  408.