Skip to content

Commit d7cb15a

Browse files
author
郑树新
committed
Rewrite and fixed bug in pthread_patch.c for windows platform in fiber module.
1 parent a3ca3d2 commit d7cb15a

6 files changed

Lines changed: 127 additions & 74 deletions

File tree

lib_fiber/c/src/common/pthread_patch.c

Lines changed: 105 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ int pthread_key_create(pthread_key_t* key, void (*destructor)(void*))
4747
if (!key)
4848
return -1;
4949

50-
DWORD k = FlsAlloc((PFLS_CALLBACK_FUNCTION)destructor);
50+
DWORD k = FlsAlloc((PFLS_KEY_FUNCTION)destructor);
5151

5252
if (k == FLS_OUT_OF_INDEXES)
5353
return -1;
@@ -122,69 +122,108 @@ int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
122122

123123
#include "common/htable.h"
124124

125-
typedef struct FLS_KEY FLS_KEY;
126-
typedef struct TLS_KEY TLS_KEY;
127-
128-
struct FLS_KEY {
129-
HTABLE *keys;
130-
};
131-
132-
struct TLS_KEY {
125+
typedef struct TLS_KEY {
133126
pthread_key_t key;
134127
void (*destructor)(void *);
135-
FIFO *objs;
136-
};
128+
} TLS_KEY;
129+
130+
typedef struct TLS_OBJ {
131+
pthread_key_t key;
132+
void *value;
133+
} TLS_OBJ;
137134

138-
static pthread_key_t __tls_key = TLS_OUT_OF_INDEXES;
139-
static pthread_key_t __fls_key = FLS_OUT_OF_INDEXES;
135+
typedef struct FLS_KEY {
136+
FIFO *locals; // Hold TLS_OBJ
137+
} FLS_KEY;
138+
139+
typedef struct PROC_KEYS {
140+
HTABLE *keys; // tkey => TLS_KEY
141+
} PROC_KEYS;
142+
143+
static pthread_key_t __tls_key = TLS_OUT_OF_INDEXES;
144+
static pthread_key_t __fls_key = FLS_OUT_OF_INDEXES;
145+
static PROC_KEYS *__pkeys = NULL;
146+
static pthread_mutex_t __lock;
140147

141148
extern int acl_fiber_scheduled(void);
142149

150+
static void hash_key(pthread_key_t key, char *buf, size_t n)
151+
{
152+
assert(n > 10);
153+
_snprintf(buf, n, "%d", key);
154+
buf[n - 1] = '\0';
155+
}
156+
143157
static void thread_exit(void *ctx)
144158
{
145159
FLS_KEY *fkey = (FLS_KEY *) ctx;
146-
void *ctx;
160+
assert(fkey && fkey->locals);
161+
162+
// The first one is set in thread_init() in fiber.c, it should be called
163+
// in the end, because the original fiber will be freed that it means
164+
// the current thread will be end and the thread context will freed.
165+
TLS_OBJ *first = fifo_pop_front(fkey->locals), *obj;
166+
assert(first);
147167

148-
assert(fkey);
149-
assert(fkey->keys);
168+
char key[32];
150169

151-
ITER iter;
152-
foreach(iter, fkey->keys) {
153-
TLS_KEY *tkey = (TLS_KEY *) iter.data;
154-
assert(tkey);
170+
pthread_mutex_lock(&__lock);
155171

156-
if (tkey->destructor == NULL) {
172+
while ((obj = fifo_pop_front(fkey->locals))) {
173+
hash_key(obj->key, key, sizeof(key));
174+
TLS_KEY *tkey = (TLS_KEY*) htable_find(__pkeys->keys, key);
175+
if (tkey == NULL || tkey->destructor == NULL) {
157176
continue;
158177
}
178+
tkey->destructor(obj->value);
179+
mem_free(obj);
180+
}
159181

160-
while ((ctx = tkey->objs->pop_front(tkey->objs))) {
161-
tkey->destructor(ctx);
162-
}
182+
fifo_free(fkey->locals, NULL);
183+
mem_free(fkey);
163184

164-
fifo_free(tkey->objs, NULL);
165-
}
185+
hash_key(first->key, key, sizeof(key));
186+
TLS_KEY *tkey = (TLS_KEY*) htable_find(__pkeys->keys, key);
187+
assert(tkey);
166188

167-
htable_free(tkey->keys, mem_free);
168-
mem_free(tkey);
169-
}
189+
pthread_mutex_unlock(&__lock);
190+
191+
void *value = first->value;
192+
mem_free(first);
170193

171-
/* 每个进程的唯一初始化函数 */
194+
// Must the __fls_key's value to NULL to avoid the thread_exit
195+
// to be triggered again for the current thread when the original
196+
// fiber is deleted.
197+
FlsSetValue(__fls_key, NULL);
198+
tkey->destructor(value);
199+
}
172200

173201
static void thread_once(void)
174202
{
175203
__tls_key = TlsAlloc();
176204
__fls_key = FlsAlloc(thread_exit);
205+
__pkeys = (PROC_KEYS *) mem_calloc(1, sizeof(PROC_KEYS));
206+
__pkeys->keys = htable_create(10);
207+
pthread_mutex_init(&__lock, NULL);
177208
}
178209

179-
static void hash_key(pthread_key_t key, char *buf, size_t n)
210+
void pthread_fkey_create(void)
180211
{
181-
assert(n > 10);
182-
_snprintf(buf, n, "%d", key);
183-
buf[n - 1] = '\0';
212+
pthread_once(&__control_once, thread_once);
213+
214+
FLS_KEY *fkey = (FLS_KEY*) TlsGetValue(__tls_key);
215+
if (fkey == NULL) {
216+
assert(!acl_fiber_scheduled());
217+
fkey = (FLS_KEY*) mem_calloc(sizeof(FLS_KEY), 1);
218+
fkey->locals = fifo_new();
219+
FlsSetValue(__fls_key, fkey);
220+
TlsSetValue(__tls_key, fkey);
221+
}
184222
}
185223

186224
int pthread_key_create(pthread_key_t *key_ptr, void (*destructor)(void*))
187225
{
226+
char kbuf[32];
188227
pthread_once(&__control_once, thread_once);
189228

190229
assert(__tls_key != TLS_OUT_OF_INDEXES);
@@ -193,73 +232,72 @@ int pthread_key_create(pthread_key_t *key_ptr, void (*destructor)(void*))
193232
if (*key_ptr <= 0 && *key_ptr != TLS_OUT_OF_INDEXES) {
194233
*key_ptr = TlsAlloc();
195234
assert(*key_ptr != TLS_OUT_OF_INDEXES);
235+
} else {
236+
hash_key(*key_ptr, kbuf, sizeof(kbuf));
237+
pthread_mutex_lock(&__lock);
238+
if (htable_find(__pkeys->keys, kbuf)) {
239+
pthread_mutex_unlock(&__lock);
240+
return 0;
241+
}
242+
*key_ptr = TlsAlloc();
243+
assert(*key_ptr != TLS_OUT_OF_INDEXES);
196244
}
197245

198-
TLS_KEY *tkey = (TLS_KEY*) mem_calloc(sizeof(TLS_KEY), 1);
246+
TLS_KEY *tkey = (TLS_KEY*) mem_calloc(sizeof(TLS_KEY), 1);
199247
tkey->key = *key_ptr;
200248
tkey->destructor = destructor;
201-
tkey->objs = fifo_new();
202249

203-
char kbuf[32];
204250
hash_key(*key_ptr, kbuf, sizeof(kbuf));
205-
FLS_KEY *fkey;
206-
207-
if ((fkey = (FLS_KEY *) TlsGetValue(__tls_key)) == NULL) {
208-
if (acl_fiber_scheduled()) {
209-
msg_fatal("%s(%d): should be in thread mode",
210-
__FUNCTION__, __LINE__);
211-
}
212251

213-
fkey = (FLS_KEY *) mem_calloc(sizeof(FLS_KEY), 1);
214-
fkey->keys = htable_create(10);
215-
216-
TlsSetValue(__tls_key, fkey);
217-
FlsSetValue(__fls_key, fkey);
218-
}
219-
220-
htable_enter(fkey->keys, kbuf, tkey);
252+
pthread_mutex_lock(&__lock);
253+
htable_enter(__pkeys->keys, kbuf, tkey);
254+
pthread_mutex_unlock(&__lock);
221255
return 0;
222256
}
223257

224-
void *pthread_getspecific(pthread_key_t key)
225-
{
226-
return TlsGetValue(key);
227-
}
228-
229258
int pthread_setspecific(pthread_key_t key, void *value)
230259
{
231260
if (key < 0 || key == TLS_OUT_OF_INDEXES) {
232261
msg_error("%s(%d): key(%d) invalid", __FUNCTION__, __LINE__, key);
233262
return EINVAL;
234263
}
235264

236-
FLS_KEY *fkey = (FLS_KEY *) TlsGetValue(__tls_key);
237-
if (fkey == NULL) {
238-
msg_error("%s(%d): no FLS_KEY for __tls_key=%d",
239-
__FUNCTION__, __LINE__, __fls_key);
240-
return EINVAL;
241-
}
265+
assert(__tls_key != TLS_OUT_OF_INDEXES);
266+
assert(__pkeys);
242267

243268
char kbuf[32];
244269
hash_key(key, kbuf, sizeof(kbuf));
245270

246-
TLS_KEY *tkey = (TLS_KEY *) htable_find(fkey->keys, kbuf);
271+
pthread_mutex_lock(&__lock);
272+
TLS_KEY *tkey = (TLS_KEY*) htable_find(__pkeys->keys, kbuf);
273+
pthread_mutex_unlock(&__lock);
274+
247275
if (tkey == NULL) {
248-
msg_error("%s(%d): no TLS_KEY for key=%d, __tls_key=%d",
249-
__FUNCTION__, __LINE__, key, __tls_key);
276+
msg_error("%s(%d): no TLS_KEY for key=%d", __FUNCTION__, __LINE__, key);
250277
return EINVAL;
251278
}
252279

280+
FLS_KEY *fkey = (FLS_KEY*) TlsGetValue(__tls_key);
281+
assert(fkey && fkey->locals);
282+
TLS_OBJ *obj = (TLS_OBJ*) mem_calloc(1, sizeof(TLS_OBJ));
283+
obj->key = key;
284+
obj->value = value;
285+
fkey->locals->push_back(fkey->locals, obj);
286+
253287
if (!TlsSetValue(key, value)) {
254288
msg_error("%s(%d): TlsSetValue(key=%d) error(%s)",
255289
__FUNCTION__, __LINE__, key, last_serror());
256290
return -1;
257291
}
258292

259-
tkey->objs->push_back(tkey->objs, value);
260293
return 0;
261294
}
262295

296+
void *pthread_getspecific(pthread_key_t key)
297+
{
298+
return TlsGetValue(key);
299+
}
300+
263301
#endif /* USE_FLS */
264302

265303
/* Free the mutex */

lib_fiber/c/src/common/pthread_patch.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ struct pthread_mutexattr_t {
3030

3131
FIBER_API int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));
3232
int pthread_key_create(pthread_key_t *key_ptr, void (*destructor)(void*));
33+
void pthread_fkey_create(void);
3334

3435
void *pthread_getspecific(pthread_key_t key);
3536
int pthread_setspecific(pthread_key_t key, void *value);

lib_fiber/c/src/fiber.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ static void thread_free(THREAD *tf)
120120
fiber = tf->original;
121121
mem_free(tf);
122122

123+
// Make sure the original fiber is the last one to be freed.
123124
fiber_real_free(fiber);
124125
}
125126

@@ -182,6 +183,8 @@ static void thread_init(void)
182183
ring_init(&local->dead);
183184

184185
#ifdef THREAD_LOCAL_DYNAMIC
186+
pthread_fkey_create();
187+
185188
if (pthread_setspecific(__fiber_key, local) != 0) {
186189
printf("pthread_setspecific error!\r\n");
187190
abort();
@@ -845,13 +848,16 @@ void acl_fiber_schedule_with(int event_mode)
845848
acl_fiber_schedule();
846849
}
847850

848-
#if defined(_WIN32) || defined(_WIN64)
851+
#ifdef _TEST
852+
# if defined(_WIN32) || defined(_WIN64)
849853
static pthread_key_t dummy_key;
850854

851855
static void thread_exit_dummy(void* ctx fiber_unused)
852856
{
853-
msg_info("%s(%d): schedule end now, key=%d\r\n", __FUNCTION__, __LINE__, dummy_key);
857+
msg_info("%s(%d): thread=%ld, schedule end now, key=%d\r\n",
858+
__FUNCTION__, __LINE__, thread_self(), dummy_key);
854859
}
860+
# endif
855861
#endif
856862

857863
void acl_fiber_schedule(void)
@@ -867,11 +873,15 @@ void acl_fiber_schedule(void)
867873
set_time_metric(1000);
868874
#endif
869875

870-
#if defined(_WIN32) || defined(_WIN64)
876+
#ifdef _TEST
877+
# if defined(_WIN32) || defined(_WIN64)
871878
// On windows, the __tls_key in pthread_key_create() must be created in no
872879
// fiber mode, because the destructor set in FlsAlloc must in no fiber mode.
873880
// See: https://github.com/acl-dev/acl/issues/363
881+
pthread_fkey_create();
874882
pthread_key_create(&dummy_key, thread_exit_dummy);
883+
pthread_setspecific(dummy_key, NULL);
884+
# endif
875885
#endif
876886

877887
fiber_check();
@@ -897,7 +907,10 @@ void acl_fiber_schedule(void)
897907
}
898908

899909
/* Release dead fiber */
900-
while ((head = ring_pop_head(&__thread_local->dead)) != NULL) {
910+
THREAD *local = __thread_local;
911+
assert(local);
912+
913+
while ((head = ring_pop_head(&local->dead)) != NULL) {
901914
fiber = RING_TO_APPL(head, ACL_FIBER, me);
902915
fiber_free(fiber);
903916
}

lib_fiber/c/src/fiber/fiber_win.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,9 @@ void acl_fiber_stackfree(ACL_FIBER_STACK *stack)
5656
void fiber_real_free(ACL_FIBER *fiber)
5757
{
5858
FIBER_WIN *fb = (FIBER_WIN *) fiber;
59-
DeleteFiber(fb->context);
59+
LPVOID ctx = fb->context;
6060
stack_free(fb);
61+
DeleteFiber(ctx);
6162
}
6263

6364
void fiber_real_swap(ACL_FIBER *from, ACL_FIBER *to)

lib_fiber/c/src/fiber_io.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,6 @@ static void fiber_io_loop(ACL_FIBER *self fiber_unused, void *ctx)
316316

317317
// Don't set ev_fiber NULL here, using fiber_io_clear() to set it NULL
318318
// in acl_fiber_schedule() after scheduling finished.
319-
//
320319
}
321320

322321
void fiber_io_clear(void)

lib_fiber/samples-c++1x/httpc/httpc.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ static void usage(const char* procname) {
5151

5252
static void fiber_main(ACL_FIBER *, void*) {
5353
printf("hello world!\r\n");
54+
acl::fiber::delay(100);
5455
}
5556

5657
static void test() {
@@ -68,7 +69,7 @@ int main(int argc, char *argv[]) {
6869
acl::acl_cpp_init();
6970
acl::log::stdout_open(true);
7071

71-
test(); return 0;
72+
test();
7273

7374
while ((ch = getopt(argc, argv, "he:s:c:n:")) > 0) {
7475
switch (ch) {

0 commit comments

Comments
 (0)