aboutsummaryrefslogtreecommitdiffstats
path: root/include/threads.h
blob: a11405f78d870f48c79c27d43d9edb7db28c77a0 (plain)
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
#ifndef AL_THREADS_H
#define AL_THREADS_H

#include <time.h>

#ifdef __cplusplus
extern "C" {
#endif

enum {
    althrd_success = 0,
    althrd_error,
    althrd_nomem,
    althrd_timedout,
    althrd_busy
};

enum {
    almtx_plain = 0,
    almtx_recursive = 1,
    almtx_timed = 2
};

typedef int (*althrd_start_t)(void*);
typedef void (*altss_dtor_t)(void*);


#define AL_TIME_UTC 1


#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>


#if !defined(_TIMESPEC_DEFINED) && !(defined(_MSC_VER) && (_MSC_VER >= 1900))
#define _TIMESPEC_DEFINED
struct timespec {
    time_t tv_sec;
    long tv_nsec;
};

struct itimerspec {
    struct timespec it_interval;
    struct timespec it_value;
};
#endif

typedef DWORD althrd_t;
typedef CRITICAL_SECTION almtx_t;
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600
typedef CONDITION_VARIABLE alcnd_t;
#else
typedef struct { void *Ptr; } alcnd_t;
#endif
typedef DWORD altss_t;
typedef LONG alonce_flag;

#define AL_ONCE_FLAG_INIT 0

int althrd_sleep(const struct timespec *ts, struct timespec *rem);
void alcall_once(alonce_flag *once, void (*callback)(void));


inline althrd_t althrd_current(void)
{
    return GetCurrentThreadId();
}

inline int althrd_equal(althrd_t thr0, althrd_t thr1)
{
    return thr0 == thr1;
}

inline void althrd_exit(int res)
{
    ExitThread(res);
}

inline void althrd_yield(void)
{
    SwitchToThread();
}


inline int almtx_lock(almtx_t *mtx)
{
    if(!mtx) return althrd_error;
    EnterCriticalSection(mtx);
    return althrd_success;
}

inline int almtx_unlock(almtx_t *mtx)
{
    if(!mtx) return althrd_error;
    LeaveCriticalSection(mtx);
    return althrd_success;
}

inline int almtx_trylock(almtx_t *mtx)
{
    if(!mtx) return althrd_error;
    if(!TryEnterCriticalSection(mtx))
        return althrd_busy;
    return althrd_success;
}


inline void *altss_get(altss_t tss_id)
{
    return TlsGetValue(tss_id);
}

inline int altss_set(altss_t tss_id, void *val)
{
    if(TlsSetValue(tss_id, val) == 0)
        return althrd_error;
    return althrd_success;
}

#else

#include <stdint.h>
#include <errno.h>
#include <pthread.h>


typedef pthread_t althrd_t;
typedef pthread_mutex_t almtx_t;
typedef pthread_cond_t alcnd_t;
typedef pthread_key_t altss_t;
typedef pthread_once_t alonce_flag;

#define AL_ONCE_FLAG_INIT PTHREAD_ONCE_INIT


inline althrd_t althrd_current(void)
{
    return pthread_self();
}

inline int althrd_equal(althrd_t thr0, althrd_t thr1)
{
    return pthread_equal(thr0, thr1);
}

inline void althrd_exit(int res)
{
    pthread_exit((void*)(intptr_t)res);
}

inline void althrd_yield(void)
{
    sched_yield();
}

inline int althrd_sleep(const struct timespec *ts, struct timespec *rem)
{
    int ret = nanosleep(ts, rem);
    if(ret != 0)
    {
        ret = ((errno==EINTR) ? -1 : -2);
        errno = 0;
    }
    return ret;
}


inline int almtx_lock(almtx_t *mtx)
{
    if(pthread_mutex_lock(mtx) != 0)
        return althrd_error;
    return althrd_success;
}

inline int almtx_unlock(almtx_t *mtx)
{
    if(pthread_mutex_unlock(mtx) != 0)
        return althrd_error;
    return althrd_success;
}

inline int almtx_trylock(almtx_t *mtx)
{
    int ret = pthread_mutex_trylock(mtx);
    switch(ret)
    {
        case 0: return althrd_success;
        case EBUSY: return althrd_busy;
    }
    return althrd_error;
}


inline void *altss_get(altss_t tss_id)
{
    return pthread_getspecific(tss_id);
}

inline int altss_set(altss_t tss_id, void *val)
{
    if(pthread_setspecific(tss_id, val) != 0)
        return althrd_error;
    return althrd_success;
}


inline void alcall_once(alonce_flag *once, void (*callback)(void))
{
    pthread_once(once, callback);
}

#endif


int althrd_create(althrd_t *thr, althrd_start_t func, void *arg);
int althrd_detach(althrd_t thr);
int althrd_join(althrd_t thr, int *res);
void althrd_setname(althrd_t thr, const char *name);

int almtx_init(almtx_t *mtx, int type);
void almtx_destroy(almtx_t *mtx);
int almtx_timedlock(almtx_t *mtx, const struct timespec *ts);

int alcnd_init(alcnd_t *cond);
int alcnd_signal(alcnd_t *cond);
int alcnd_broadcast(alcnd_t *cond);
int alcnd_wait(alcnd_t *cond, almtx_t *mtx);
int alcnd_timedwait(alcnd_t *cond, almtx_t *mtx, const struct timespec *time_point);
void alcnd_destroy(alcnd_t *cond);

int altss_create(altss_t *tss_id, altss_dtor_t callback);
void altss_delete(altss_t tss_id);

int altimespec_get(struct timespec *ts, int base);

void al_nssleep(unsigned long nsec);

#ifdef __cplusplus
}
#endif

#endif /* AL_THREADS_H */