OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [win32-threads.cc] - Blame information for rev 867

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 753 jeremybenn
// win32-threads.cc - interface between libjava and Win32 threads.
2
 
3
/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2006 Free Software
4
   Foundation, Inc.
5
 
6
   This file is part of libgcj.
7
 
8
This software is copyrighted work licensed under the terms of the
9
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
10
details.  */
11
 
12
#include <config.h>
13
 
14
// If we're using the Boehm GC, then we need to override some of the
15
// thread primitives.  This is fairly gross.
16
#ifdef HAVE_BOEHM_GC
17
extern "C"
18
{
19
#include <gc.h>
20
// <windows.h> #define's STRICT, which conflicts with Modifier.h
21
#undef STRICT
22
};
23
#endif /* HAVE_BOEHM_GC */
24
 
25
#include <gcj/cni.h>
26
#include <jvm.h>
27
#include <java/lang/Thread.h>
28
#include <java/lang/System.h>
29
 
30
#include <errno.h>
31
 
32
#ifndef ETIMEDOUT
33
#define ETIMEDOUT 116
34
#endif
35
 
36
// This is used to implement thread startup.
37
struct starter
38
{
39
  _Jv_ThreadStartFunc *method;
40
  _Jv_Thread_t *data;
41
};
42
 
43
// Controls access to the variable below
44
static HANDLE daemon_mutex;
45
static HANDLE daemon_cond;
46
// Number of non-daemon threads - _Jv_ThreadWait returns when this is 0
47
static int non_daemon_count;
48
 
49
// TLS key get Java object representing the thread
50
DWORD _Jv_ThreadKey;
51
// TLS key to get _Jv_Thread_t* representing the thread
52
DWORD _Jv_ThreadDataKey;
53
 
54
//
55
// These are the flags that can appear in _Jv_Thread_t.
56
//
57
 
58
// Thread started.
59
#define FLAG_START   0x01
60
// Thread is daemon.
61
#define FLAG_DAEMON  0x02
62
 
63
//
64
// Helper
65
//
66
inline bool
67
compare_and_exchange(LONG volatile* dest, LONG cmp, LONG xchg)
68
{
69
  return InterlockedCompareExchange((LONG*) dest, xchg, cmp) == cmp;
70
    // Seems like a bug in the MinGW headers that we have to do this cast.
71
}
72
 
73
//
74
// Condition variables.
75
//
76
 
77
// we do lazy creation of Events since CreateEvent() is insanely
78
// expensive, and because the rest of libgcj will call _Jv_CondInit
79
// when only a mutex is needed.
80
 
81
inline void
82
ensure_condvar_initialized(_Jv_ConditionVariable_t *cv)
83
{
84
  if (cv->ev[0] == 0)
85
    {
86
      cv->ev[0] = CreateEvent (NULL, 0, 0, NULL);
87
      if (cv->ev[0] == 0) JvFail("CreateEvent() failed");
88
 
89
      cv->ev[1] = CreateEvent (NULL, 1, 0, NULL);
90
      if (cv->ev[1] == 0) JvFail("CreateEvent() failed");
91
    }
92
}
93
 
94
inline void
95
ensure_interrupt_event_initialized(HANDLE& rhEvent)
96
{
97
  if (!rhEvent)
98
    {
99
      rhEvent = CreateEvent (NULL, 0, 0, NULL);
100
      if (!rhEvent) JvFail("CreateEvent() failed");
101
    }
102
}
103
 
104
// Reimplementation of the general algorithm described at
105
// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html (isomorphic to
106
// 3.2, not a cut-and-paste).
107
 
108
int
109
_Jv_CondWait(_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu, jlong millis, jint nanos)
110
{
111
  if (mu->owner != GetCurrentThreadId ( ))
112
    return _JV_NOT_OWNER;
113
 
114
  _Jv_Thread_t *current = _Jv_ThreadCurrentData ();
115
  java::lang::Thread *current_obj = _Jv_ThreadCurrent ();
116
 
117
  // Now that we hold the interrupt mutex, check if this thread has been 
118
  // interrupted already.
119
  EnterCriticalSection (&current->interrupt_mutex);
120
  ensure_interrupt_event_initialized (current->interrupt_event);
121
  jboolean interrupted = current_obj->interrupt_flag;
122
  LeaveCriticalSection (&current->interrupt_mutex);
123
 
124
  if (interrupted)
125
    {
126
      return _JV_INTERRUPTED;
127
    }
128
 
129
  EnterCriticalSection (&cv->count_mutex);
130
  ensure_condvar_initialized (cv);
131
  cv->blocked_count++;
132
  LeaveCriticalSection (&cv->count_mutex);
133
 
134
  DWORD time;
135
  if ((millis == 0) && (nanos > 0)) time = 1;
136
  else if (millis == 0) time = INFINITE;
137
  else time = millis;
138
 
139
  // Record the current lock depth, so it can be restored
140
  // when we reacquire it.
141
  int count = mu->refcount;
142
  int curcount = count;
143
 
144
  // Call _Jv_MutexUnlock repeatedly until this thread
145
  // has completely released the monitor.
146
  while (curcount > 0)
147
    {
148
      _Jv_MutexUnlock (mu);
149
      --curcount;
150
    }
151
 
152
  // Set up our array of three events:
153
  // - the auto-reset event (for notify())
154
  // - the manual-reset event (for notifyAll())
155
  // - the interrupt event (for interrupt())
156
  // We wait for any one of these to be signaled.
157
  HANDLE arh[3];
158
  arh[0] = cv->ev[0];
159
  arh[1] = cv->ev[1];
160
  arh[2] = current->interrupt_event;
161
  DWORD rval = WaitForMultipleObjects (3, arh, 0, time);
162
 
163
  EnterCriticalSection (&current->interrupt_mutex);
164
 
165
  // If we were unblocked by the third event (our thread's interrupt
166
  // event), set the thread's interrupt flag. I think this sanity
167
  // check guards against someone resetting our interrupt flag
168
  // in the time between when interrupt_mutex is released in
169
  // _Jv_ThreadInterrupt and the interval of time between the
170
  // WaitForMultipleObjects call we just made and our acquisition
171
  // of interrupt_mutex.
172
  if (rval == (WAIT_OBJECT_0 + 2))
173
    current_obj->interrupt_flag = true;
174
 
175
  interrupted = current_obj->interrupt_flag;
176
  LeaveCriticalSection (&current->interrupt_mutex);
177
 
178
  EnterCriticalSection(&cv->count_mutex);
179
  cv->blocked_count--;
180
  // If we were unblocked by the second event (the broadcast one)
181
  // and nobody is left, then reset the event.
182
  int last_waiter = (rval == (WAIT_OBJECT_0 + 1)) && (cv->blocked_count == 0);
183
  LeaveCriticalSection(&cv->count_mutex);
184
 
185
  if (last_waiter)
186
    ResetEvent (cv->ev[1]);
187
 
188
  // Call _Jv_MutexLock repeatedly until the mutex's refcount is the
189
  // same as before we originally released it.
190
  while (curcount < count)
191
    {
192
      _Jv_MutexLock (mu);
193
      ++curcount;
194
    }
195
 
196
  return interrupted ? _JV_INTERRUPTED : 0;
197
}
198
 
199
void
200
_Jv_CondInit (_Jv_ConditionVariable_t *cv)
201
{
202
  // we do lazy creation of Events since CreateEvent() is insanely expensive
203
  cv->ev[0] = 0;
204
  InitializeCriticalSection (&cv->count_mutex);
205
  cv->blocked_count = 0;
206
}
207
 
208
void
209
_Jv_CondDestroy (_Jv_ConditionVariable_t *cv)
210
{
211
  if (cv->ev[0] != 0)
212
    {
213
      CloseHandle (cv->ev[0]);
214
      CloseHandle (cv->ev[1]);
215
 
216
      cv->ev[0] = 0;
217
    }
218
 
219
  DeleteCriticalSection (&cv->count_mutex);
220
}
221
 
222
int
223
_Jv_CondNotify (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu)
224
{
225
  if (mu->owner != GetCurrentThreadId ( ))
226
    return _JV_NOT_OWNER;
227
 
228
  EnterCriticalSection (&cv->count_mutex);
229
  ensure_condvar_initialized (cv);
230
  int somebody_is_blocked = cv->blocked_count > 0;
231
  LeaveCriticalSection (&cv->count_mutex);
232
 
233
  if (somebody_is_blocked)
234
    SetEvent (cv->ev[0]);
235
 
236
  return 0;
237
}
238
 
239
int
240
_Jv_CondNotifyAll (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu)
241
{
242
  if (mu->owner != GetCurrentThreadId ( ))
243
    return _JV_NOT_OWNER;
244
 
245
  EnterCriticalSection (&cv->count_mutex);
246
  ensure_condvar_initialized (cv);
247
  int somebody_is_blocked = cv->blocked_count > 0;
248
  LeaveCriticalSection (&cv->count_mutex);
249
 
250
  if (somebody_is_blocked)
251
    SetEvent (cv->ev[1]);
252
 
253
  return 0;
254
}
255
 
256
//
257
// Threads.
258
//
259
 
260
void
261
_Jv_InitThreads (void)
262
{
263
  _Jv_ThreadKey = TlsAlloc();
264
  _Jv_ThreadDataKey = TlsAlloc();
265
  daemon_mutex = CreateMutex (NULL, 0, NULL);
266
  daemon_cond = CreateEvent (NULL, 1, 0, NULL);
267
  non_daemon_count = 0;
268
}
269
 
270
_Jv_Thread_t *
271
_Jv_ThreadInitData (java::lang::Thread* obj)
272
{
273
  _Jv_Thread_t *data = (_Jv_Thread_t*)_Jv_Malloc(sizeof(_Jv_Thread_t));
274
  data->flags = 0;
275
  data->handle = 0;
276
  data->thread_obj = obj;
277
  data->interrupt_event = 0;
278
  InitializeCriticalSection (&data->interrupt_mutex);
279
 
280
  return data;
281
}
282
 
283
void
284
_Jv_ThreadDestroyData (_Jv_Thread_t *data)
285
{
286
  DeleteCriticalSection (&data->interrupt_mutex);
287
  if (data->interrupt_event)
288
    CloseHandle(data->interrupt_event);
289
  CloseHandle(data->handle);
290
  _Jv_Free(data);
291
}
292
 
293
void
294
_Jv_ThreadSetPriority (_Jv_Thread_t *data, jint prio)
295
{
296
  int actual = THREAD_PRIORITY_NORMAL;
297
 
298
  if (data->flags & FLAG_START)
299
    {
300
      switch (prio)
301
        {
302
          case 10:
303
            actual = THREAD_PRIORITY_TIME_CRITICAL;
304
            break;
305
          case 9:
306
            actual = THREAD_PRIORITY_HIGHEST;
307
            break;
308
          case 8:
309
          case 7:
310
            actual = THREAD_PRIORITY_ABOVE_NORMAL;
311
            break;
312
          case 6:
313
          case 5:
314
            actual = THREAD_PRIORITY_NORMAL;
315
            break;
316
          case 4:
317
          case 3:
318
            actual = THREAD_PRIORITY_BELOW_NORMAL;
319
            break;
320
          case 2:
321
            actual = THREAD_PRIORITY_LOWEST;
322
            break;
323
          case 1:
324
            actual = THREAD_PRIORITY_IDLE;
325
            break;
326
        }
327
      SetThreadPriority(data->handle, actual);
328
    }
329
}
330
 
331
void
332
_Jv_ThreadRegister (_Jv_Thread_t *data)
333
{
334
  TlsSetValue (_Jv_ThreadKey, data->thread_obj);
335
  TlsSetValue (_Jv_ThreadDataKey, data);
336
}
337
 
338
void
339
_Jv_ThreadUnRegister ()
340
{
341
  TlsSetValue (_Jv_ThreadKey, NULL);
342
  TlsSetValue (_Jv_ThreadDataKey, NULL);
343
}
344
 
345
// This function is called when a thread is started.  We don't arrange
346
// to call the `run' method directly, because this function must
347
// return a value.
348
static DWORD WINAPI
349
really_start (void* x)
350
{
351
  struct starter *info = (struct starter *) x;
352
 
353
  _Jv_ThreadRegister (info->data);
354
 
355
  info->method (info->data->thread_obj);
356
 
357
  if (! (info->data->flags & FLAG_DAEMON))
358
    {
359
      WaitForSingleObject (daemon_mutex, INFINITE);
360
      non_daemon_count--;
361
      if (! non_daemon_count)
362
        SetEvent (daemon_cond);
363
      ReleaseMutex (daemon_mutex);
364
    }
365
 
366
  return 0;
367
}
368
 
369
void
370
_Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data, _Jv_ThreadStartFunc *meth)
371
{
372
  DWORD id;
373
  struct starter *info;
374
 
375
  // Do nothing if thread has already started
376
  if (data->flags & FLAG_START)
377
    return;
378
  data->flags |= FLAG_START;
379
 
380
  info = (struct starter *) _Jv_AllocBytes (sizeof (struct starter));
381
  info->method = meth;
382
  info->data = data;
383
 
384
  if (! thread->isDaemon ())
385
    {
386
      WaitForSingleObject (daemon_mutex, INFINITE);
387
      non_daemon_count++;
388
      ReleaseMutex (daemon_mutex);
389
    }
390
  else
391
    data->flags |= FLAG_DAEMON;
392
 
393
  data->handle = GC_CreateThread(NULL, 0, really_start, info, 0, &id);
394
  _Jv_ThreadSetPriority(data, thread->getPriority());
395
}
396
 
397
void
398
_Jv_ThreadWait (void)
399
{
400
  WaitForSingleObject (daemon_mutex, INFINITE);
401
  if (non_daemon_count)
402
    {
403
      ReleaseMutex (daemon_mutex);
404
      WaitForSingleObject (daemon_cond, INFINITE);
405
    }
406
}
407
 
408
//
409
// Interrupt support
410
//
411
 
412
HANDLE
413
_Jv_Win32GetInterruptEvent (void)
414
{
415
  _Jv_Thread_t *current = _Jv_ThreadCurrentData ();
416
  EnterCriticalSection (&current->interrupt_mutex);
417
  ensure_interrupt_event_initialized (current->interrupt_event);
418
  HANDLE hEvent = current->interrupt_event;
419
  LeaveCriticalSection (&current->interrupt_mutex);
420
  return hEvent;
421
}
422
 
423
void
424
_Jv_ThreadInterrupt (_Jv_Thread_t *data)
425
{
426
  EnterCriticalSection (&data->interrupt_mutex);
427
  ensure_interrupt_event_initialized (data->interrupt_event);
428
  data->thread_obj->interrupt_flag = true;
429
  SetEvent (data->interrupt_event);
430
  LeaveCriticalSection (&data->interrupt_mutex);
431
}
432
 
433
// park() / unpark() support
434
 
435
void
436
ParkHelper::init ()
437
{
438
  // We initialize our critical section, but not our event.
439
  InitializeCriticalSection (&cs);
440
  event = NULL;
441
}
442
 
443
void
444
ParkHelper::init_event()
445
{
446
  EnterCriticalSection (&cs);
447
  if (!event)
448
    {
449
      // Create an auto-reset event.
450
      event = CreateEvent(NULL, 0, 0, NULL);
451
      if (!event) JvFail("CreateEvent() failed");
452
    }
453
  LeaveCriticalSection (&cs);
454
}
455
 
456
void
457
ParkHelper::deactivate ()
458
{
459
  permit = ::java::lang::Thread::THREAD_PARK_DEAD;
460
}
461
 
462
void
463
ParkHelper::destroy()
464
{
465
  if (event) CloseHandle (event);
466
  DeleteCriticalSection (&cs);
467
}
468
 
469
/**
470
 * Releases the block on a thread created by _Jv_ThreadPark().  This
471
 * method can also be used to terminate a blockage caused by a prior
472
 * call to park.  This operation is unsafe, as the thread must be
473
 * guaranteed to be live.
474
 *
475
 * @param thread the thread to unblock.
476
 */
477
void
478
ParkHelper::unpark ()
479
{
480
  using namespace ::java::lang;
481
  LONG volatile* ptr = &permit;
482
 
483
  // If this thread is in state RUNNING, give it a permit and return
484
  // immediately.
485
  if (compare_and_exchange
486
      (ptr, Thread::THREAD_PARK_RUNNING, Thread::THREAD_PARK_PERMIT))
487
    return;
488
 
489
  // If this thread is parked, put it into state RUNNING and send it a
490
  // signal.
491
  if (compare_and_exchange
492
      (ptr, Thread::THREAD_PARK_PARKED, Thread::THREAD_PARK_RUNNING))
493
    {
494
      init_event ();
495
      SetEvent (event);
496
    }
497
}
498
 
499
/**
500
 * Blocks the thread until a matching _Jv_ThreadUnpark() occurs, the
501
 * thread is interrupted or the optional timeout expires.  If an
502
 * unpark call has already occurred, this also counts.  A timeout
503
 * value of zero is defined as no timeout.  When isAbsolute is true,
504
 * the timeout is in milliseconds relative to the epoch.  Otherwise,
505
 * the value is the number of nanoseconds which must occur before
506
 * timeout.  This call may also return spuriously (i.e.  for no
507
 * apparent reason).
508
 *
509
 * @param isAbsolute true if the timeout is specified in milliseconds from
510
 *                   the epoch.
511
 * @param time either the number of nanoseconds to wait, or a time in
512
 *             milliseconds from the epoch to wait for.
513
 */
514
void
515
ParkHelper::park (jboolean isAbsolute, jlong time)
516
{
517
  using namespace ::java::lang;
518
  LONG volatile* ptr = &permit;
519
 
520
  // If we have a permit, return immediately.
521
  if (compare_and_exchange
522
      (ptr, Thread::THREAD_PARK_PERMIT, Thread::THREAD_PARK_RUNNING))
523
    return;
524
 
525
  // Determine the number of milliseconds to wait.
526
  jlong millis = 0, nanos = 0;
527
 
528
  if (time)
529
    {
530
      if (isAbsolute)
531
        {
532
          millis = time - ::java::lang::System::currentTimeMillis();
533
          nanos = 0;
534
        }
535
      else
536
        {
537
          millis = 0;
538
          nanos = time;
539
        }
540
 
541
      if (nanos)
542
        {
543
          millis += nanos / 1000000;
544
          if (millis == 0)
545
            millis = 1;
546
            // ...otherwise, we'll block indefinitely.
547
        }
548
    }
549
 
550
  if (millis < 0) return;
551
      // Can this ever happen?
552
 
553
  if (compare_and_exchange
554
      (ptr, Thread::THREAD_PARK_RUNNING, Thread::THREAD_PARK_PARKED))
555
    {
556
      init_event();
557
 
558
      DWORD timeout = millis==0 ? INFINITE : (DWORD) millis;
559
      WaitForSingleObject (event, timeout);
560
 
561
      // If we were unparked by some other thread, this will already
562
      // be in state THREAD_PARK_RUNNING.  If we timed out, we have to
563
      // do it ourself.
564
      compare_and_exchange
565
        (ptr, Thread::THREAD_PARK_PARKED, Thread::THREAD_PARK_RUNNING);
566
    }
567
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.