Path: blob/master/libsnes/libco_debugging/libco_win32threads.c
2 views
/*1win32 implementation of libco using actual threads. much slower than other implementations,2but far from glacial. may be useful for debuggers that don't understand libco cothreads.34compiles in mingw. try:5gcc libco_win32threads.c -o libco.dll -Wall -shared -O0 -g6*/78#include <stdlib.h>9#include <assert.h> // asserts don't happen in co_switch(), so no real performance gain from turning them off10#define LIBCO_C11#include "libco.h"12#define WIN32_LEAN_AND_MEAN13#include <windows.h>1415typedef struct16{17HANDLE thread;18HANDLE sem;19int wantdie;20void (*entrypoint)(void);21} coprivate;2223static __thread coprivate *libco_priv = NULL;242526/*27Return handle to current cothread. Always returns a valid handle, even when called from the main program thread.28*/29cothread_t co_active(void)30{31if (!libco_priv)32{33// thread started out as a real thread, so we must make a libco_priv for it34libco_priv = malloc(sizeof (*libco_priv));35assert(libco_priv);36DWORD ret = DuplicateHandle37(38GetCurrentProcess(),39GetCurrentThread(),40GetCurrentProcess(),41&libco_priv->thread,420,43FALSE,44DUPLICATE_SAME_ACCESS45);46assert(ret);47libco_priv->sem = CreateSemaphore(NULL, 0, 1, NULL);48assert(libco_priv->sem);49libco_priv->wantdie = 0;50libco_priv->entrypoint = NULL;51}52return (cothread_t) libco_priv;53}5455void waittorun(void)56{57// i suppose it would be possible to switch off the main thread58// without ever having made a context for it. then it would never59// be able to activate again.60coprivate *this = (coprivate *) co_active();61WaitForSingleObject(this->sem, INFINITE);62if (this->wantdie)63{64CloseHandle(this->sem);65ExitThread(0);66}67}6869DWORD WINAPI thread_entry(LPVOID lpParameter)70{71libco_priv = (coprivate *) lpParameter;72waittorun();73libco_priv->entrypoint();74assert(0); // returning from entry point not allowed75return 0;76}7778/*79Create new cothread.80Heapsize is the amount of memory allocated for the cothread stack, specified in bytes. This is unfortunately impossible to make fully portable. It is recommended to specify sizes using `n * sizeof(void*)'. It is better to err on the side of caution and allocate more memory than will be needed to ensure compatibility with other platforms, within reason. A typical heapsize for a 32-bit architecture is ~1MB.81When the new cothread is first called, program execution jumps to coentry. This function does not take any arguments, due to portability issues with passing function arguments. However, arguments can be simulated by the use of global variables, which can be set before the first call to each cothread.82coentry() must not return, and should end with an appropriate co_switch() statement. Behavior is undefined if entry point returns normally.83Library is responsible for allocating cothread stack memory, to free the user from needing to allocate special memory capable of being used as program stack memory on platforms where this is required.84User is always responsible for deleting cothreads with co_delete().85Return value of null (0) indicates cothread creation failed.86*/87cothread_t co_create(unsigned int heapsize, void (*entry)(void))88{89coprivate *new_thread = malloc(sizeof (*new_thread));90assert(new_thread);91new_thread->sem = CreateSemaphore(NULL, 0, 1, NULL);92assert(new_thread->sem);93new_thread->wantdie = 0;94new_thread->entrypoint = entry;95assert(new_thread->entrypoint);96new_thread->thread = CreateThread97(98NULL,99heapsize,100thread_entry,101(void *)new_thread,1020, // runs immediately103NULL104);105assert(new_thread->thread);106return (cothread_t) new_thread;107}108109/*110Delete specified cothread.111Null (0) or invalid cothread handle is not allowed.112Passing handle of active cothread to this function is not allowed.113Passing handle of primary cothread is not allowed.114*/115void co_delete(cothread_t _thread)116{117coprivate *thread = (coprivate *) _thread;118assert(thread);119assert(thread->entrypoint); // Passing handle of primary cothread is not allowed120thread->wantdie = 1;121ReleaseSemaphore(thread->sem, 1, NULL);122WaitForSingleObject(thread->thread, INFINITE);123CloseHandle(thread->thread);124free(thread);125}126127/*128Switch to specified cothread.129Null (0) or invalid cothread handle is not allowed.130Passing handle of active cothread to this function is not allowed.131*/132void co_switch(cothread_t _thread)133{134coprivate *thread = (coprivate *) _thread;135ReleaseSemaphore(thread->sem, 1, NULL);136waittorun();137}138139140