~ubuntu-branches/ubuntu/quantal/nspr/quantal-security

« back to all changes in this revision

Viewing changes to mozilla/nsprpub/pr/src/md/windows/w16thred.c

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack
  • Date: 2009-08-10 11:34:26 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090810113426-3uv4diflrkcbdimm
Tags: 4.8-0ubuntu1
* New upstream release: 4.8 (LP: #387812)
* adjust patches to changed upstreanm codebase
  - update debian/patches/99_configure.patch
* update shlibs symbols to include new API elements
  - update debian/libnspr4-0d.symbols

Show diffs side-by-side

added added

removed removed

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