- pid_t old_pid;
- int finished=0;
- do {
- get_spinlock(&all_threads_lock,th->pid);
- for(p=all_threads,old_pid=p->pid; p; p=p->next) {
- if(p==th) continue;
- if(p->state!=STATE_RUNNING) continue;
- p->state=STATE_STOPPING;
- kill(p->pid,SIG_STOP_FOR_GC);
- }
- release_spinlock(&all_threads_lock);
- sched_yield();
- /* if everything has stopped, and there is no possibility that
- * a new thread has been created, we're done. Otherwise go
- * round again and signal anything that sprang up since last
- * time */
- if(old_pid==all_threads->pid) {
- finished=1;
- for_each_thread(p)
- finished = finished &&
- ((p==th) || (p->state==STATE_STOPPED));
- }
- } while(!finished);
+ /* keep threads from starting while the world is stopped. */
+ get_spinlock(&thread_start_lock,th->pid);
+#ifdef QSHOW_SIGNALS
+ SHOW("gc_stop_the_world:locked");
+#endif
+ /* stop all other threads by sending them SIG_STOP_FOR_GC */
+ for(p=all_threads; p; p=p->next) {
+ if((p!=th) && (p->pid!=0) && (p->state==STATE_RUNNING)) {
+ p->state=STATE_STOPPING;
+ if(kill(p->pid,SIG_STOP_FOR_GC)==-1) {
+ /* we can't kill the process; assume because it
+ * died already (and its parent is dead so never
+ * saw the SIGCHLD) */
+ p->state=STATE_DEAD;
+ }
+ }
+ }
+#ifdef QSHOW_SIGNALS
+ SHOW("gc_stop_the_world:signals sent");
+#endif
+ /* wait for the running threads to stop */
+ for(p=all_threads;p;) {
+ if((p==th) || (p->pid==0) || (p->state==STATE_STARTING) ||
+ (p->state==STATE_DEAD) || (p->state==STATE_STOPPED)) {
+ p=p->next;
+ }
+ }
+#ifdef QSHOW_SIGNALS
+ SHOW("gc_stop_the_world:end");
+#endif