+ if (! CONFIG_THREADS) {
+ check_irqs32();
+ return;
+ }
+ struct thread_info *cur = getCurThread();
+ if (cur == &MainThread)
+ // Permit irqs to fire
+ check_irqs32();
+
+ // Switch to the next thread
+ struct thread_info *next = cur->next;
+ asm volatile(
+ " pushl $1f\n" // store return pc
+ " pushl %%ebp\n" // backup %ebp
+ " movl %%esp, 4(%%eax)\n" // cur->stackpos = %esp
+ " movl 4(%%ecx), %%esp\n" // %esp = next->stackpos
+ " popl %%ebp\n" // restore %ebp
+ " retl\n" // restore pc
+ "1:\n"
+ : "+a"(cur), "+c"(next)
+ :
+ : "ebx", "edx", "esi", "edi", "cc", "memory");
+}
+
+// Last thing called from a thread (called on "next" stack).
+static void
+__end_thread(struct thread_info *old)
+{
+ struct thread_info *pos = &MainThread;
+ while (pos->next != old)
+ pos = pos->next;
+ pos->next = old->next;
+ free(old);
+ dprintf(2, "=========== end thread %p\n", old);
+}
+
+void
+run_thread(void (*func)(void*), void *data)
+{
+ ASSERT32();
+ if (! CONFIG_THREADS)
+ goto fail;
+ struct thread_info *thread;
+ thread = memalign_tmphigh(THREADSTACKSIZE, THREADSTACKSIZE);
+ if (!thread)
+ goto fail;
+
+ thread->stackpos = (void*)thread + THREADSTACKSIZE;
+ struct thread_info *cur = getCurThread();
+ thread->next = cur->next;
+ cur->next = thread;
+
+ dprintf(2, "=========== start thread %p\n", thread);
+ asm volatile(
+ // Start thread
+ " pushl $1f\n" // store return pc
+ " pushl %%ebp\n" // backup %ebp
+ " movl %%esp, 4(%%edx)\n" // cur->stackpos = %esp
+ " movl 4(%%ebx), %%esp\n" // %esp = thread->stackpos
+ " calll *%%ecx\n" // Call func
+
+ // End thread
+ " movl (%%ebx), %%ecx\n" // %ecx = thread->next
+ " movl 4(%%ecx), %%esp\n" // %esp = next->stackpos
+ " movl %%ebx, %%eax\n"
+ " calll %4\n" // call __end_thread(thread)
+ " popl %%ebp\n" // restore %ebp
+ " retl\n" // restore pc
+ "1:\n"
+ : "+a"(data), "+c"(func), "+b"(thread), "+d"(cur)
+ : "m"(*(u8*)__end_thread)
+ : "esi", "edi", "cc", "memory");
+ return;
+
+fail:
+ func(data);
+}
+
+void
+wait_threads()
+{
+ ASSERT32();
+ if (! CONFIG_THREADS)
+ return;
+ while (MainThread.next != &MainThread)
+ yield();