Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libsnes/libco_debugging/libco_win32threads.c
2 views
1
/*
2
win32 implementation of libco using actual threads. much slower than other implementations,
3
but far from glacial. may be useful for debuggers that don't understand libco cothreads.
4
5
compiles in mingw. try:
6
gcc libco_win32threads.c -o libco.dll -Wall -shared -O0 -g
7
*/
8
9
#include <stdlib.h>
10
#include <assert.h> // asserts don't happen in co_switch(), so no real performance gain from turning them off
11
#define LIBCO_C
12
#include "libco.h"
13
#define WIN32_LEAN_AND_MEAN
14
#include <windows.h>
15
16
typedef struct
17
{
18
HANDLE thread;
19
HANDLE sem;
20
int wantdie;
21
void (*entrypoint)(void);
22
} coprivate;
23
24
static __thread coprivate *libco_priv = NULL;
25
26
27
/*
28
Return handle to current cothread. Always returns a valid handle, even when called from the main program thread.
29
*/
30
cothread_t co_active(void)
31
{
32
if (!libco_priv)
33
{
34
// thread started out as a real thread, so we must make a libco_priv for it
35
libco_priv = malloc(sizeof (*libco_priv));
36
assert(libco_priv);
37
DWORD ret = DuplicateHandle
38
(
39
GetCurrentProcess(),
40
GetCurrentThread(),
41
GetCurrentProcess(),
42
&libco_priv->thread,
43
0,
44
FALSE,
45
DUPLICATE_SAME_ACCESS
46
);
47
assert(ret);
48
libco_priv->sem = CreateSemaphore(NULL, 0, 1, NULL);
49
assert(libco_priv->sem);
50
libco_priv->wantdie = 0;
51
libco_priv->entrypoint = NULL;
52
}
53
return (cothread_t) libco_priv;
54
}
55
56
void waittorun(void)
57
{
58
// i suppose it would be possible to switch off the main thread
59
// without ever having made a context for it. then it would never
60
// be able to activate again.
61
coprivate *this = (coprivate *) co_active();
62
WaitForSingleObject(this->sem, INFINITE);
63
if (this->wantdie)
64
{
65
CloseHandle(this->sem);
66
ExitThread(0);
67
}
68
}
69
70
DWORD WINAPI thread_entry(LPVOID lpParameter)
71
{
72
libco_priv = (coprivate *) lpParameter;
73
waittorun();
74
libco_priv->entrypoint();
75
assert(0); // returning from entry point not allowed
76
return 0;
77
}
78
79
/*
80
Create new cothread.
81
Heapsize 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.
82
When 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.
83
coentry() must not return, and should end with an appropriate co_switch() statement. Behavior is undefined if entry point returns normally.
84
Library 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.
85
User is always responsible for deleting cothreads with co_delete().
86
Return value of null (0) indicates cothread creation failed.
87
*/
88
cothread_t co_create(unsigned int heapsize, void (*entry)(void))
89
{
90
coprivate *new_thread = malloc(sizeof (*new_thread));
91
assert(new_thread);
92
new_thread->sem = CreateSemaphore(NULL, 0, 1, NULL);
93
assert(new_thread->sem);
94
new_thread->wantdie = 0;
95
new_thread->entrypoint = entry;
96
assert(new_thread->entrypoint);
97
new_thread->thread = CreateThread
98
(
99
NULL,
100
heapsize,
101
thread_entry,
102
(void *)new_thread,
103
0, // runs immediately
104
NULL
105
);
106
assert(new_thread->thread);
107
return (cothread_t) new_thread;
108
}
109
110
/*
111
Delete specified cothread.
112
Null (0) or invalid cothread handle is not allowed.
113
Passing handle of active cothread to this function is not allowed.
114
Passing handle of primary cothread is not allowed.
115
*/
116
void co_delete(cothread_t _thread)
117
{
118
coprivate *thread = (coprivate *) _thread;
119
assert(thread);
120
assert(thread->entrypoint); // Passing handle of primary cothread is not allowed
121
thread->wantdie = 1;
122
ReleaseSemaphore(thread->sem, 1, NULL);
123
WaitForSingleObject(thread->thread, INFINITE);
124
CloseHandle(thread->thread);
125
free(thread);
126
}
127
128
/*
129
Switch to specified cothread.
130
Null (0) or invalid cothread handle is not allowed.
131
Passing handle of active cothread to this function is not allowed.
132
*/
133
void co_switch(cothread_t _thread)
134
{
135
coprivate *thread = (coprivate *) _thread;
136
ReleaseSemaphore(thread->sem, 1, NULL);
137
waittorun();
138
}
139
140