]>
Commit | Line | Data |
---|---|---|
878885b4 TT |
1 | // win32-threads.cc - interface between libjava and Win32 threads. |
2 | ||
3 | /* Copyright (C) 1998, 1999 Red Hat, Inc. | |
4 | ||
5 | This file is part of libgcj. | |
6 | ||
7 | This software is copyrighted work licensed under the terms of the | |
8 | Libgcj License. Please consult the file "LIBGCJ_LICENSE" for | |
9 | details. */ | |
10 | ||
11 | #include <config.h> | |
12 | ||
13 | // If we're using the Boehm GC, then we need to override some of the | |
14 | // thread primitives. This is fairly gross. | |
15 | #ifdef HAVE_BOEHM_GC | |
16 | extern "C" | |
17 | { | |
18 | #include <boehm-config.h> | |
19 | #include <gc.h> | |
20 | }; | |
21 | #endif /* HAVE_BOEHM_GC */ | |
22 | ||
23 | #include <gcj/cni.h> | |
24 | #include <jvm.h> | |
25 | #include <java/lang/Thread.h> | |
26 | #include <java/lang/System.h> | |
27 | ||
28 | #include <errno.h> | |
29 | ||
30 | #ifndef ETIMEDOUT | |
31 | #define ETIMEDOUT 116 | |
32 | #endif | |
33 | ||
34 | // This is used to implement thread startup. | |
35 | struct starter | |
36 | { | |
37 | _Jv_ThreadStartFunc *method; | |
38 | java::lang::Thread *object; | |
39 | _Jv_Thread_t *data; | |
40 | }; | |
41 | ||
42 | // Controls access to the variable below | |
43 | static HANDLE daemon_mutex; | |
44 | static HANDLE daemon_cond; | |
45 | // Number of non-daemon threads - _Jv_ThreadWait returns when this is 0 | |
46 | static int non_daemon_count; | |
47 | ||
48 | // TLS key get Java object representing the thread | |
49 | DWORD _Jv_ThreadKey; | |
50 | // TLS key to get _Jv_Thread_t* representing the thread | |
51 | DWORD _Jv_ThreadDataKey; | |
52 | ||
53 | // | |
54 | // These are the flags that can appear in _Jv_Thread_t. | |
55 | // | |
56 | ||
57 | // Thread started. | |
58 | #define FLAG_START 0x01 | |
59 | // Thread is daemon. | |
60 | #define FLAG_DAEMON 0x02 | |
61 | ||
62 | // | |
63 | // Condition variables. | |
64 | // | |
65 | ||
66 | int | |
67 | _Jv_CondWait (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu, jlong millis, jint nanos) | |
68 | { | |
69 | DWORD time; | |
70 | DWORD rval; | |
71 | ||
72 | _Jv_MutexUnlock (mu); | |
73 | ||
74 | if((millis == 0) && (nanos > 0)) | |
75 | time = 1; | |
76 | else if(millis == 0) | |
77 | time = INFINITE; | |
78 | else | |
79 | time = millis; | |
80 | ||
81 | rval = WaitForSingleObject (*cv, time); | |
82 | _Jv_MutexLock (mu); | |
83 | ||
84 | if (rval == WAIT_FAILED) | |
85 | return GetLastError (); // FIXME: Map to errno? | |
86 | else if (rval == WAIT_TIMEOUT) | |
87 | return ETIMEDOUT; | |
88 | else | |
89 | return 0; | |
90 | } | |
91 | ||
92 | // | |
93 | // Mutexes. | |
94 | // | |
95 | ||
96 | int | |
97 | _Jv_MutexLock (_Jv_Mutex_t *mu) | |
98 | { | |
99 | DWORD rval; | |
100 | ||
101 | // FIXME: Are Win32 mutexs recursive? Should we use critical section objects | |
102 | rval = WaitForSingleObject (*mu, INFINITE); | |
103 | ||
104 | if (rval == WAIT_FAILED) | |
105 | return GetLastError (); // FIXME: Map to errno? | |
106 | else if (rval == WAIT_TIMEOUT) | |
107 | return ETIMEDOUT; | |
108 | else | |
109 | return 0; | |
110 | } | |
111 | ||
112 | // | |
113 | // Threads. | |
114 | // | |
115 | ||
116 | void | |
117 | _Jv_InitThreads (void) | |
118 | { | |
119 | _Jv_ThreadKey = TlsAlloc(); | |
120 | _Jv_ThreadDataKey = TlsAlloc(); | |
121 | daemon_mutex = CreateMutex(NULL, 0, NULL); | |
122 | daemon_cond = CreateEvent(NULL, 0, 0, NULL); | |
123 | non_daemon_count = 0; | |
124 | } | |
125 | ||
126 | void | |
127 | _Jv_ThreadInitData (_Jv_Thread_t **data, java::lang::Thread *) | |
128 | { | |
129 | _Jv_Thread_t *info = new _Jv_Thread_t; | |
130 | info->flags = 0; | |
131 | ||
132 | // FIXME register a finalizer for INFO here. | |
133 | // FIXME also must mark INFO somehow. | |
134 | ||
135 | *data = info; | |
136 | } | |
137 | ||
138 | void | |
139 | _Jv_ThreadSetPriority (_Jv_Thread_t *data, jint prio) | |
140 | { | |
141 | int actual = THREAD_PRIORITY_NORMAL; | |
142 | ||
143 | if (data->flags & FLAG_START) | |
144 | { | |
145 | switch (prio) | |
146 | { | |
147 | case 10: | |
148 | actual = THREAD_PRIORITY_TIME_CRITICAL; | |
149 | break; | |
150 | case 9: | |
151 | actual = THREAD_PRIORITY_HIGHEST; | |
152 | break; | |
153 | case 8: | |
154 | case 7: | |
155 | actual = THREAD_PRIORITY_ABOVE_NORMAL; | |
156 | break; | |
157 | case 6: | |
158 | case 5: | |
159 | actual = THREAD_PRIORITY_NORMAL; | |
160 | break; | |
161 | case 4: | |
162 | case 3: | |
163 | actual = THREAD_PRIORITY_BELOW_NORMAL; | |
164 | break; | |
165 | case 2: | |
166 | actual = THREAD_PRIORITY_LOWEST; | |
167 | break; | |
168 | case 1: | |
169 | actual = THREAD_PRIORITY_IDLE; | |
170 | break; | |
171 | } | |
172 | SetThreadPriority(data->handle, actual); | |
173 | } | |
174 | } | |
175 | ||
176 | // This function is called when a thread is started. We don't arrange | |
177 | // to call the `run' method directly, because this function must | |
178 | // return a value. | |
179 | static DWORD __stdcall | |
180 | really_start (void* x) | |
181 | { | |
182 | struct starter *info = (struct starter *) x; | |
183 | ||
184 | TlsSetValue (_Jv_ThreadKey, info->object); | |
185 | TlsSetValue (_Jv_ThreadDataKey, info->data); | |
186 | info->method (info->object); | |
187 | ||
188 | if (! (info->data->flags & FLAG_DAEMON)) | |
189 | { | |
190 | WaitForSingleObject (daemon_mutex, INFINITE); | |
191 | non_daemon_count--; | |
192 | if (! non_daemon_count) | |
193 | PulseEvent (daemon_cond); | |
194 | ReleaseMutex (daemon_mutex); | |
195 | } | |
196 | ||
197 | return 0; | |
198 | } | |
199 | ||
200 | void | |
201 | _Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data, _Jv_ThreadStartFunc *meth) | |
202 | { | |
203 | DWORD id; | |
204 | struct starter *info; | |
205 | ||
206 | // Do nothing if thread has already started | |
207 | if (data->flags & FLAG_START) | |
208 | return; | |
209 | data->flags |= FLAG_START; | |
210 | ||
211 | // FIXME: handle marking the info object for GC. | |
212 | info = (struct starter *) _Jv_AllocBytes (sizeof (struct starter)); | |
213 | info->method = meth; | |
214 | info->object = thread; | |
215 | info->data = data; | |
216 | ||
217 | if (! thread->isDaemon ()) | |
218 | { | |
219 | WaitForSingleObject (daemon_mutex, INFINITE); | |
220 | non_daemon_count++; | |
221 | ReleaseMutex (daemon_mutex); | |
222 | } | |
223 | else | |
224 | data->flags |= FLAG_DAEMON; | |
225 | ||
226 | HANDLE h = CreateThread(NULL, 0, really_start, info, 0, &id); | |
227 | _Jv_ThreadSetPriority(data, thread->getPriority()); | |
228 | ||
229 | //if (!h) | |
230 | //JvThrow (); | |
231 | } | |
232 | ||
233 | void | |
234 | _Jv_ThreadWait (void) | |
235 | { | |
236 | WaitForSingleObject(daemon_mutex, INFINITE); | |
237 | if(non_daemon_count) | |
238 | SignalObjectAndWait(daemon_mutex, daemon_cond, INFINITE, 0); | |
239 | ReleaseMutex(daemon_mutex); | |
240 | } | |
241 | ||
242 | void | |
243 | _Jv_ThreadInterrupt (_Jv_Thread_t *data) | |
244 | { | |
245 | MessageBox(NULL, "Unimplemented", "win32-threads.cc:_Jv_ThreadInterrupt", MB_OK); | |
246 | // FIXME: | |
247 | } |