Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 #include "runtime.h" | 5 #include "runtime.h" |
6 #include "type.h" | 6 #include "type.h" |
7 #include "defs.h" | 7 #include "defs.h" |
8 #include "os.h" | 8 #include "os.h" |
9 | 9 |
10 #pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll" | 10 #pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll" |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
49 extern void *runtime·SetConsoleCtrlHandler; | 49 extern void *runtime·SetConsoleCtrlHandler; |
50 extern void *runtime·SetEvent; | 50 extern void *runtime·SetEvent; |
51 extern void *runtime·SetThreadPriority; | 51 extern void *runtime·SetThreadPriority; |
52 extern void *runtime·SetWaitableTimer; | 52 extern void *runtime·SetWaitableTimer; |
53 extern void *runtime·SuspendThread; | 53 extern void *runtime·SuspendThread; |
54 extern void *runtime·timeBeginPeriod; | 54 extern void *runtime·timeBeginPeriod; |
55 extern void *runtime·WaitForSingleObject; | 55 extern void *runtime·WaitForSingleObject; |
56 extern void *runtime·WriteFile; | 56 extern void *runtime·WriteFile; |
57 | 57 |
58 static int64 timerfreq; | 58 static int64 timerfreq; |
59 static void destroylock(Lock *l); | |
60 | 59 |
61 void | 60 void |
62 runtime·osinit(void) | 61 runtime·osinit(void) |
63 { | 62 { |
64 // -1 = current process, -2 = current thread | 63 // -1 = current process, -2 = current thread |
65 runtime·stdcall(runtime·DuplicateHandle, 7, | 64 runtime·stdcall(runtime·DuplicateHandle, 7, |
66 (uintptr)-1, (uintptr)-2, (uintptr)-1, &m->thread, | 65 (uintptr)-1, (uintptr)-2, (uintptr)-1, &m->thread, |
67 (uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS); | 66 (uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS); |
68 runtime·stdcall(runtime·QueryPerformanceFrequency, 1, &timerfreq); | 67 runtime·stdcall(runtime·QueryPerformanceFrequency, 1, &timerfreq); |
69 runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, ( uintptr)1); | 68 runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, ( uintptr)1); |
70 runtime·stdcall(runtime·timeBeginPeriod, 1, (uintptr)1); | 69 runtime·stdcall(runtime·timeBeginPeriod, 1, (uintptr)1); |
brainman
2011/09/15 02:45:40
I would delay it until you really need it. Not eve
hector
2011/09/15 06:17:30
Yes, but the tick rate will also affect the accura
| |
71 runtime·destroylock = destroylock; | |
72 } | 70 } |
73 | 71 |
74 void | 72 void |
75 runtime·goenvs(void) | 73 runtime·goenvs(void) |
76 { | 74 { |
77 extern Slice os·Envs; | 75 extern Slice os·Envs; |
78 | 76 |
79 uint16 *env; | 77 uint16 *env; |
80 String *s; | 78 String *s; |
81 int32 i, n; | 79 int32 i, n; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
134 { | 132 { |
135 void *event; | 133 void *event; |
136 | 134 |
137 event = runtime·stdcall(runtime·CreateEvent, 4, (uintptr)0, (uintptr)0, (uintptr)0, (uintptr)0); | 135 event = runtime·stdcall(runtime·CreateEvent, 4, (uintptr)0, (uintptr)0, (uintptr)0, (uintptr)0); |
138 if(!runtime·casp(pevent, 0, event)) { | 136 if(!runtime·casp(pevent, 0, event)) { |
139 // Someone else filled it in. Use theirs. | 137 // Someone else filled it in. Use theirs. |
140 runtime·stdcall(runtime·CloseHandle, 1, event); | 138 runtime·stdcall(runtime·CloseHandle, 1, event); |
141 } | 139 } |
142 } | 140 } |
143 | 141 |
142 #define LOCK_HELD ((M*)-1) | |
143 | |
144 static void | 144 static void |
145 eventlock(Lock *l) | 145 eventlock(Lock *l) |
146 { | 146 { |
147 // Allocate event if needed. | 147 // Allocate event if needed. |
148 » if(l->event == 0) | 148 » if(m->event == nil) |
149 » » initevent(&l->event); | 149 » » initevent(&m->event); |
150 | 150 |
151 » if(runtime·xadd(&l->key, 1) > 1)» // someone else has it; wait | 151 » for(;;) { |
152 » » runtime·stdcall(runtime·WaitForSingleObject, 2, l->event, (uintp tr)-1); | 152 » » m->nextwaitm = runtime·atomicloadp(&l->waitm); |
153 » » if(m->nextwaitm == nil) { | |
154 » » » if(runtime·casp(&l->waitm, nil, LOCK_HELD)) | |
155 » » » » return; | |
156 » » // Someone else has it. | |
157 » » // l->waitm points to a linked list of M's waiting | |
158 » » // for this lock, chained through m->nextwaitm. | |
159 » » // Queue this M. | |
160 » » } else if(runtime·casp(&l->waitm, m->nextwaitm, m)) | |
161 » » » break; | |
162 » } | |
163 | |
164 » // Wait. | |
165 » runtime·stdcall(runtime·WaitForSingleObject, 2, m->event, (uintptr)-1); | |
153 } | 166 } |
154 | 167 |
155 static void | 168 static void |
156 eventunlock(Lock *l) | 169 eventunlock(Lock *l) |
157 { | 170 { |
158 » if(runtime·xadd(&l->key, -1) > 0)» // someone else is waiting | 171 » M *mp; |
159 » » runtime·stdcall(runtime·SetEvent, 1, l->event); | 172 |
173 » for(;;) { | |
174 » » mp = runtime·atomicloadp(&l->waitm); | |
175 » » if(mp == LOCK_HELD) { | |
176 » » » if(runtime·casp(&l->waitm, LOCK_HELD, nil)) | |
177 » » » » return; | |
178 » » // Other M's are waiting for the lock. | |
179 » » // Dequeue a M. | |
180 » » } else if(runtime·casp(&l->waitm, mp, mp->nextwaitm)) | |
181 » » » break; | |
182 » } | |
183 | |
184 » // Wake that M. | |
185 » runtime·stdcall(runtime·SetEvent, 1, mp->event); | |
160 } | 186 } |
161 | 187 |
162 void | 188 void |
163 runtime·lock(Lock *l) | 189 runtime·lock(Lock *l) |
164 { | 190 { |
165 if(m->locks < 0) | 191 if(m->locks < 0) |
166 runtime·throw("lock count"); | 192 runtime·throw("lock count"); |
167 m->locks++; | 193 m->locks++; |
168 eventlock(l); | 194 eventlock(l); |
169 } | 195 } |
170 | 196 |
171 void | 197 void |
172 runtime·unlock(Lock *l) | 198 runtime·unlock(Lock *l) |
173 { | 199 { |
174 m->locks--; | 200 m->locks--; |
175 if(m->locks < 0) | 201 if(m->locks < 0) |
176 runtime·throw("lock count"); | 202 runtime·throw("lock count"); |
177 eventunlock(l); | 203 eventunlock(l); |
178 } | 204 } |
179 | 205 |
180 static void | |
181 destroylock(Lock *l) | |
182 { | |
183 if(l->event != 0) | |
184 runtime·stdcall(runtime·CloseHandle, 1, l->event); | |
185 } | |
186 | |
187 void | 206 void |
188 runtime·noteclear(Note *n) | 207 runtime·noteclear(Note *n) |
189 { | 208 { |
190 » n->lock.key = 0;» // memset(n, 0, sizeof *n) | 209 » n->lock.waitm = nil; |
191 eventlock(&n->lock); | 210 eventlock(&n->lock); |
192 } | 211 } |
193 | 212 |
194 void | 213 void |
195 runtime·notewakeup(Note *n) | 214 runtime·notewakeup(Note *n) |
196 { | 215 { |
197 eventunlock(&n->lock); | 216 eventunlock(&n->lock); |
198 } | 217 } |
199 | 218 |
200 void | 219 void |
201 runtime·notesleep(Note *n) | 220 runtime·notesleep(Note *n) |
202 { | 221 { |
203 eventlock(&n->lock); | 222 eventlock(&n->lock); |
204 eventunlock(&n->lock); // Let other sleepers find out too. | 223 eventunlock(&n->lock); // Let other sleepers find out too. |
205 } | 224 } |
206 | 225 |
207 void | 226 void |
208 runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) | 227 runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) |
209 { | 228 { |
210 void *thandle; | 229 void *thandle; |
211 | 230 |
212 USED(stk); | 231 USED(stk); |
213 USED(g); // assuming g = m->g0 | 232 USED(g); // assuming g = m->g0 |
214 USED(fn); // assuming fn = mstart | 233 USED(fn); // assuming fn = mstart |
215 | 234 |
216 thandle = runtime·stdcall(runtime·CreateThread, 6, | 235 thandle = runtime·stdcall(runtime·CreateThread, 6, |
217 » » nil, (uintptr)0, runtime·tstart_stdcall, | 236 » » nil, nil, runtime·tstart_stdcall, m, nil, nil); |
218 » » m, (uintptr)CREATE_SUSPENDED, nil); | |
219 if(thandle == nil) { | 237 if(thandle == nil) { |
220 runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror()); | 238 runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror()); |
221 runtime·throw("runtime.newosproc"); | 239 runtime·throw("runtime.newosproc"); |
222 } | 240 } |
223 » m->thread = thandle; | 241 » runtime·atomicstorep(&m->thread, thandle); |
224 » runtime·stdcall(runtime·ResumeThread, 1, thandle); | |
225 } | 242 } |
226 | 243 |
227 // Called to initialize a new m (including the bootstrap m). | 244 // Called to initialize a new m (including the bootstrap m). |
228 void | 245 void |
229 runtime·minit(void) | 246 runtime·minit(void) |
230 { | 247 { |
231 } | 248 } |
232 | 249 |
233 void | 250 void |
234 runtime·gettime(int64 *sec, int32 *usec) | 251 runtime·gettime(int64 *sec, int32 *usec) |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
342 byte rbuf[sizeof(Context)+15]; | 359 byte rbuf[sizeof(Context)+15]; |
343 Context *r; | 360 Context *r; |
344 void *tls; | 361 void *tls; |
345 G *gp; | 362 G *gp; |
346 | 363 |
347 tls = mp->tls; | 364 tls = mp->tls; |
348 if(mp == &runtime·m0) | 365 if(mp == &runtime·m0) |
349 tls = runtime·tls0; | 366 tls = runtime·tls0; |
350 gp = *(G**)tls; | 367 gp = *(G**)tls; |
351 | 368 |
352 » if(gp != nil) { | 369 » if(gp != nil && gp != mp->g0 && gp->status != Gsyscall) { |
353 // align Context to 16 bytes | 370 // align Context to 16 bytes |
354 r = (Context*)((uintptr)(&rbuf[15]) & ~15); | 371 r = (Context*)((uintptr)(&rbuf[15]) & ~15); |
355 r->ContextFlags = CONTEXT_CONTROL; | 372 r->ContextFlags = CONTEXT_CONTROL; |
356 runtime·stdcall(runtime·GetThreadContext, 2, mp->thread, r); | 373 runtime·stdcall(runtime·GetThreadContext, 2, mp->thread, r); |
357 runtime·dosigprof(r, gp); | 374 runtime·dosigprof(r, gp); |
358 } | 375 } |
359 } | 376 } |
360 | 377 |
361 void | 378 void |
362 runtime·profileloop1(void) | 379 runtime·profileloop1(void) |
363 { | 380 { |
364 M *mp, *allm; | 381 M *mp, *allm; |
382 void *thread; | |
365 | 383 |
366 runtime·stdcall(runtime·SetThreadPriority, 2, | 384 runtime·stdcall(runtime·SetThreadPriority, 2, |
367 (uintptr)-2, (uintptr)THREAD_PRIORITY_HIGHEST); | 385 (uintptr)-2, (uintptr)THREAD_PRIORITY_HIGHEST); |
368 | 386 |
369 for(;;) { | 387 for(;;) { |
370 runtime·stdcall(runtime·WaitForSingleObject, 2, profiletimer, (u intptr)-1); | 388 runtime·stdcall(runtime·WaitForSingleObject, 2, profiletimer, (u intptr)-1); |
371 allm = runtime·atomicloadp(&runtime·allm); | 389 allm = runtime·atomicloadp(&runtime·allm); |
372 for(mp = allm; mp != nil; mp = mp->alllink) { | 390 for(mp = allm; mp != nil; mp = mp->alllink) { |
373 » » » runtime·stdcall(runtime·SuspendThread, 1, mp->thread); | 391 » » » thread = runtime·atomicloadp(&mp->thread); |
brainman
2011/09/16 02:56:42
Why do you prefer that to starting new thread susp
| |
392 » » » if(thread == nil) | |
393 » » » » continue; | |
394 » » » runtime·stdcall(runtime·SuspendThread, 1, thread); | |
374 if(mp->profilehz != 0) | 395 if(mp->profilehz != 0) |
375 profilem(mp); | 396 profilem(mp); |
376 » » » runtime·stdcall(runtime·ResumeThread, 1, mp->thread); | 397 » » » runtime·stdcall(runtime·ResumeThread, 1, thread); |
377 } | 398 } |
378 } | 399 } |
379 } | 400 } |
380 | 401 |
381 void | 402 void |
382 runtime·resetcpuprofiler(int32 hz) | 403 runtime·resetcpuprofiler(int32 hz) |
383 { | 404 { |
384 static Lock lock; | 405 static Lock lock; |
385 void *timer, *thread; | 406 void *timer, *thread; |
386 int32 ms; | 407 int32 ms; |
(...skipping 20 matching lines...) Expand all Loading... | |
407 runtime·stdcall(runtime·SetWaitableTimer, 6, | 428 runtime·stdcall(runtime·SetWaitableTimer, 6, |
408 profiletimer, &due, (uintptr)ms, nil, nil, nil); | 429 profiletimer, &due, (uintptr)ms, nil, nil, nil); |
409 runtime·atomicstore((uint32*)&m->profilehz, hz); | 430 runtime·atomicstore((uint32*)&m->profilehz, hz); |
410 } | 431 } |
411 | 432 |
412 void | 433 void |
413 os·sigpipe(void) | 434 os·sigpipe(void) |
414 { | 435 { |
415 runtime·throw("too many writes on closed pipe"); | 436 runtime·throw("too many writes on closed pipe"); |
416 } | 437 } |
LEFT | RIGHT |