forked from ossrs/state-threads
-
Notifications
You must be signed in to change notification settings - Fork 0
/
common.h
475 lines (376 loc) · 14.9 KB
/
common.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
/* SPDX-License-Identifier: MPL-1.1 OR GPL-2.0-or-later */
/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the Netscape Portable Runtime library.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s): Silicon Graphics, Inc.
*
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
* Graphics, Inc. All Rights Reserved.
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
/*
* This file is derived directly from Netscape Communications Corporation,
* and consists of extensive modifications made during the year(s) 1999-2000.
*/
#ifndef __ST_COMMON_H__
#define __ST_COMMON_H__
#include <stddef.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <setjmp.h>
/* Enable assertions only if DEBUG is defined */
#ifndef DEBUG
#define NDEBUG
#endif
#include <assert.h>
#define ST_ASSERT(expr) assert(expr)
#define ST_BEGIN_MACRO {
#define ST_END_MACRO }
#ifdef DEBUG
#define ST_HIDDEN /*nothing*/
#else
#define ST_HIDDEN static
#endif
#include "public.h"
#include "md.h"
/* merge from https://github.com/toffaletti/state-threads/commit/7f57fc9acc05e657bca1223f1e5b9b1a45ed929b */
#ifndef MD_VALGRIND
#ifndef NVALGRIND
#define NVALGRIND
#endif
#else
#undef NVALGRIND
#endif
/*****************************************
* Circular linked list definitions
*/
typedef struct _st_clist {
struct _st_clist *next;
struct _st_clist *prev;
} _st_clist_t;
/* Insert element "_e" into the list, before "_l" */
#define ST_INSERT_BEFORE(_e,_l) \
ST_BEGIN_MACRO \
(_e)->next = (_l); \
(_e)->prev = (_l)->prev; \
(_l)->prev->next = (_e); \
(_l)->prev = (_e); \
ST_END_MACRO
/* Insert element "_e" into the list, after "_l" */
#define ST_INSERT_AFTER(_e,_l) \
ST_BEGIN_MACRO \
(_e)->next = (_l)->next; \
(_e)->prev = (_l); \
(_l)->next->prev = (_e); \
(_l)->next = (_e); \
ST_END_MACRO
/* Return the element following element "_e" */
#define ST_NEXT_LINK(_e) ((_e)->next)
/* Append an element "_e" to the end of the list "_l" */
#define ST_APPEND_LINK(_e,_l) ST_INSERT_BEFORE(_e,_l)
/* Insert an element "_e" at the head of the list "_l" */
#define ST_INSERT_LINK(_e,_l) ST_INSERT_AFTER(_e,_l)
/* Return the head/tail of the list */
#define ST_LIST_HEAD(_l) (_l)->next
#define ST_LIST_TAIL(_l) (_l)->prev
/* Remove the element "_e" from it's circular list */
#define ST_REMOVE_LINK(_e) \
ST_BEGIN_MACRO \
(_e)->prev->next = (_e)->next; \
(_e)->next->prev = (_e)->prev; \
ST_END_MACRO
/* Return non-zero if the given circular list "_l" is empty, */
/* zero if the circular list is not empty */
#define ST_CLIST_IS_EMPTY(_l) \
((_l)->next == (_l))
/* Initialize a circular list */
#define ST_INIT_CLIST(_l) \
ST_BEGIN_MACRO \
(_l)->next = (_l); \
(_l)->prev = (_l); \
ST_END_MACRO
#define ST_INIT_STATIC_CLIST(_l) \
{(_l), (_l)}
/*****************************************
* Basic types definitions
*/
typedef void (*_st_destructor_t)(void *);
typedef struct _st_stack {
_st_clist_t links;
char *vaddr; /* Base of stack's allocated memory */
int vaddr_size; /* Size of stack's allocated memory */
int stk_size; /* Size of usable portion of the stack */
char *stk_bottom; /* Lowest address of stack's usable portion */
char *stk_top; /* Highest address of stack's usable portion */
void *sp; /* Stack pointer from C's point of view */
/* merge from https://github.com/toffaletti/state-threads/commit/7f57fc9acc05e657bca1223f1e5b9b1a45ed929b */
#ifndef NVALGRIND
/* id returned by VALGRIND_STACK_REGISTER */
/* http://valgrind.org/docs/manual/manual-core-adv.html */
unsigned long valgrind_stack_id;
#endif
} _st_stack_t;
typedef struct _st_cond {
_st_clist_t wait_q; /* Condition variable wait queue */
} _st_cond_t;
typedef struct _st_thread _st_thread_t;
struct _st_thread {
int state; /* Thread's state */
int flags; /* Thread's flags */
void *(*start)(void *arg); /* The start function of the thread */
void *arg; /* Argument of the start function */
void *retval; /* Return value of the start function */
_st_stack_t *stack; /* Info about thread's stack */
_st_clist_t links; /* For putting on run/sleep/zombie queue */
_st_clist_t wait_links; /* For putting on mutex/condvar wait queue */
#ifdef DEBUG
_st_clist_t tlink; /* For putting on thread queue */
#endif
st_utime_t due; /* Wakeup time when thread is sleeping */
_st_thread_t *left; /* For putting in timeout heap */
_st_thread_t *right; /* -- see docs/timeout_heap.txt for details */
int heap_index;
void **private_data; /* Per thread private data */
_st_cond_t *term; /* Termination condition variable for join */
_st_jmp_buf_t context; /* Thread's context */
};
typedef struct _st_mutex {
_st_thread_t *owner; /* Current mutex owner */
_st_clist_t wait_q; /* Mutex wait queue */
} _st_mutex_t;
typedef struct _st_pollq {
_st_clist_t links; /* For putting on io queue */
_st_thread_t *thread; /* Polling thread */
struct pollfd *pds; /* Array of poll descriptors */
int npds; /* Length of the array */
int on_ioq; /* Is it on ioq? */
} _st_pollq_t;
typedef struct _st_eventsys_ops {
const char *name; /* Name of this event system */
int val; /* Type of this event system */
int (*init)(void); /* Initialization */
void (*dispatch)(void); /* Dispatch function */
int (*pollset_add)(struct pollfd *, int); /* Add descriptor set */
void (*pollset_del)(struct pollfd *, int); /* Delete descriptor set */
int (*fd_new)(int); /* New descriptor allocated */
int (*fd_close)(int); /* Descriptor closed */
int (*fd_getlimit)(void); /* Descriptor hard limit */
void (*destroy)(void); /* Destroy the event object */
} _st_eventsys_t;
typedef struct _st_vp {
_st_thread_t *idle_thread; /* Idle thread for this vp */
st_utime_t last_clock; /* The last time we went into vp_check_clock() */
_st_clist_t run_q; /* run queue for this vp */
_st_clist_t io_q; /* io queue for this vp */
_st_clist_t zombie_q; /* zombie queue for this vp */
#ifdef DEBUG
_st_clist_t thread_q; /* all threads of this vp */
#endif
int pagesize;
_st_thread_t *sleep_q; /* sleep queue for this vp */
int sleepq_size; /* number of threads on sleep queue */
#ifdef ST_SWITCH_CB
st_switch_cb_t switch_out_cb; /* called when a thread is switched out */
st_switch_cb_t switch_in_cb; /* called when a thread is switched in */
#endif
} _st_vp_t;
typedef struct _st_netfd {
int osfd; /* Underlying OS file descriptor */
int inuse; /* In-use flag */
void *private_data; /* Per descriptor private data */
_st_destructor_t destructor; /* Private data destructor function */
void *aux_data; /* Auxiliary data for internal use */
struct _st_netfd *next; /* For putting on the free list */
} _st_netfd_t;
/*****************************************
* Current vp, thread, and event system
*/
extern __thread _st_vp_t _st_this_vp;
extern __thread _st_thread_t *_st_this_thread;
extern __thread _st_eventsys_t *_st_eventsys;
#define _ST_CURRENT_THREAD() (_st_this_thread)
#define _ST_SET_CURRENT_THREAD(_thread) (_st_this_thread = (_thread))
#define _ST_LAST_CLOCK (_st_this_vp.last_clock)
#define _ST_RUNQ (_st_this_vp.run_q)
#define _ST_IOQ (_st_this_vp.io_q)
#define _ST_ZOMBIEQ (_st_this_vp.zombie_q)
#ifdef DEBUG
#define _ST_THREADQ (_st_this_vp.thread_q)
#endif
#define _ST_PAGE_SIZE (_st_this_vp.pagesize)
#define _ST_SLEEPQ (_st_this_vp.sleep_q)
#define _ST_SLEEPQ_SIZE (_st_this_vp.sleepq_size)
#define _ST_VP_IDLE() (*_st_eventsys->dispatch)()
/*****************************************
* vp queues operations
*/
#define _ST_ADD_IOQ(_pq) ST_APPEND_LINK(&_pq.links, &_ST_IOQ)
#define _ST_DEL_IOQ(_pq) ST_REMOVE_LINK(&_pq.links)
#define _ST_ADD_RUNQ(_thr) ST_APPEND_LINK(&(_thr)->links, &_ST_RUNQ)
#define _ST_INSERT_RUNQ(_thr) ST_INSERT_LINK(&(_thr)->links, &_ST_RUNQ)
#define _ST_DEL_RUNQ(_thr) ST_REMOVE_LINK(&(_thr)->links)
#define _ST_ADD_SLEEPQ(_thr, _timeout) _st_add_sleep_q(_thr, _timeout)
#define _ST_DEL_SLEEPQ(_thr) _st_del_sleep_q(_thr)
#define _ST_ADD_ZOMBIEQ(_thr) ST_APPEND_LINK(&(_thr)->links, &_ST_ZOMBIEQ)
#define _ST_DEL_ZOMBIEQ(_thr) ST_REMOVE_LINK(&(_thr)->links)
#ifdef DEBUG
#define _ST_ADD_THREADQ(_thr) ST_APPEND_LINK(&(_thr)->tlink, &_ST_THREADQ)
#define _ST_DEL_THREADQ(_thr) ST_REMOVE_LINK(&(_thr)->tlink)
#endif
/*****************************************
* Thread states and flags
*/
#define _ST_ST_RUNNING 0
#define _ST_ST_RUNNABLE 1
#define _ST_ST_IO_WAIT 2
#define _ST_ST_LOCK_WAIT 3
#define _ST_ST_COND_WAIT 4
#define _ST_ST_SLEEPING 5
#define _ST_ST_ZOMBIE 6
#define _ST_ST_SUSPENDED 7
#define _ST_FL_PRIMORDIAL 0x01
#define _ST_FL_IDLE_THREAD 0x02
#define _ST_FL_ON_SLEEPQ 0x04
#define _ST_FL_INTERRUPT 0x08
#define _ST_FL_TIMEDOUT 0x10
/*****************************************
* Pointer conversion
*/
#ifndef offsetof
#define offsetof(type, identifier) ((size_t)&(((type *)0)->identifier))
#endif
#define _ST_THREAD_PTR(_qp) \
((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, links)))
#define _ST_THREAD_WAITQ_PTR(_qp) \
((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, wait_links)))
#define _ST_THREAD_STACK_PTR(_qp) \
((_st_stack_t *)((char*)(_qp) - offsetof(_st_stack_t, links)))
#define _ST_POLLQUEUE_PTR(_qp) \
((_st_pollq_t *)((char *)(_qp) - offsetof(_st_pollq_t, links)))
#ifdef DEBUG
#define _ST_THREAD_THREADQ_PTR(_qp) \
((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, tlink)))
#endif
/*****************************************
* Constants
*/
#ifndef ST_UTIME_NO_TIMEOUT
#define ST_UTIME_NO_TIMEOUT ((st_utime_t) -1LL)
#endif
#define ST_DEFAULT_STACK_SIZE (128*1024) /* Includes register stack size */
#ifndef ST_KEYS_MAX
#define ST_KEYS_MAX 16
#endif
#ifndef ST_MIN_POLLFDS_SIZE
#define ST_MIN_POLLFDS_SIZE 64
#endif
/*****************************************
* Threads context switching
*/
#ifdef DEBUG
void _st_iterate_threads(void);
#define ST_DEBUG_ITERATE_THREADS() _st_iterate_threads()
#else
#define ST_DEBUG_ITERATE_THREADS()
#endif
#ifdef ST_SWITCH_CB
#define ST_SWITCH_OUT_CB(_thread) \
if (_st_this_vp.switch_out_cb != NULL && \
_thread != _st_this_vp.idle_thread && \
_thread->state != _ST_ST_ZOMBIE) { \
_st_this_vp.switch_out_cb(); \
}
#define ST_SWITCH_IN_CB(_thread) \
if (_st_this_vp.switch_in_cb != NULL && \
_thread != _st_this_vp.idle_thread && \
_thread->state != _ST_ST_ZOMBIE) { \
_st_this_vp.switch_in_cb(); \
}
#else
#define ST_SWITCH_OUT_CB(_thread)
#define ST_SWITCH_IN_CB(_thread)
#endif
/*
* Switch away from the current thread context by saving its state and
* calling the thread scheduler
*/
#define _ST_SWITCH_CONTEXT(_thread) \
ST_BEGIN_MACRO \
ST_SWITCH_OUT_CB(_thread); \
if (!MD_SETJMP((_thread)->context)) { \
_st_vp_schedule(); \
} \
ST_DEBUG_ITERATE_THREADS(); \
ST_SWITCH_IN_CB(_thread); \
ST_END_MACRO
/*
* Restore a thread context that was saved by _ST_SWITCH_CONTEXT or
* initialized by _ST_INIT_CONTEXT
*/
#define _ST_RESTORE_CONTEXT(_thread) \
ST_BEGIN_MACRO \
_ST_SET_CURRENT_THREAD(_thread); \
MD_LONGJMP((_thread)->context, 1); \
ST_END_MACRO
/*
* Initialize the thread context preparing it to execute _main
*/
#ifdef MD_INIT_CONTEXT
#define _ST_INIT_CONTEXT MD_INIT_CONTEXT
#else
#error Unknown OS
#endif
/*
* Number of bytes reserved under the stack "bottom"
*/
#define _ST_STACK_PAD_SIZE MD_STACK_PAD_SIZE
/*****************************************
* Forward declarations
*/
void _st_vp_schedule(void);
void _st_vp_check_clock(void);
void *_st_idle_thread_start(void *arg);
void _st_thread_main(void);
void _st_thread_cleanup(_st_thread_t *thread);
void _st_add_sleep_q(_st_thread_t *thread, st_utime_t timeout);
void _st_del_sleep_q(_st_thread_t *thread);
_st_stack_t *_st_stack_new(int stack_size);
void _st_stack_free(_st_stack_t *ts);
int _st_io_init(void);
st_utime_t st_utime(void);
_st_cond_t *st_cond_new(void);
int st_cond_destroy(_st_cond_t *cvar);
int st_cond_timedwait(_st_cond_t *cvar, st_utime_t timeout);
int st_cond_signal(_st_cond_t *cvar);
ssize_t st_read(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout);
ssize_t st_write(_st_netfd_t *fd, const void *buf, size_t nbyte, st_utime_t timeout);
int st_poll(struct pollfd *pds, int npds, st_utime_t timeout);
_st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stk_size);
#endif /* !__ST_COMMON_H__ */