-
Notifications
You must be signed in to change notification settings - Fork 4
/
thread-pthread.cpp
179 lines (153 loc) · 4.87 KB
/
thread-pthread.cpp
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
#include "os.h"
#if defined(__unix__)// && !defined(__linux__)
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
//list of synchronization points: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_10
struct threaddata_pthread {
function<void()> func;
};
static void * threadproc(void * userdata)
{
struct threaddata_pthread * thdat=(struct threaddata_pthread*)userdata;
thdat->func();
free(thdat);
return NULL;
}
void thread_create(function<void()> start)
{
struct threaddata_pthread * thdat=malloc(sizeof(struct threaddata_pthread));
thdat->func=start;
pthread_t thread;
if (pthread_create(&thread, NULL, threadproc, thdat)) abort();
pthread_detach(thread);
}
unsigned int thread_num_cores()
{
//for more OSes: https://qt.gitorious.org/qt/qt/source/HEAD:src/corelib/thread/qthread_unix.cpp#L411, idealThreadCount()
//or http://stackoverflow.com/questions/150355/programmatically-find-the-number-of-cores-on-a-machine
return sysconf(_SC_NPROCESSORS_ONLN);
}
mutex::mutex()
{
pthread_mutex_init(&mut, NULL);
}
void mutex::lock()
{
pthread_mutex_lock(&mut);
}
bool mutex::try_lock()
{
return (pthread_mutex_trylock(&mut)==0);
}
void mutex::unlock()
{
pthread_mutex_unlock(&mut);
}
mutex::~mutex()
{
pthread_mutex_destroy(&mut);
}
event::event()
{
this->data=malloc(sizeof(sem_t));
sem_init((sem_t*)this->data, 0, 0);
}
event::~event()
{
sem_destroy((sem_t*)this->data);
free(this->data);
}
void event::signal()
{
if (!this->signalled()) sem_post((sem_t*)this->data);
}
void event::wait()
{
sem_wait((sem_t*)this->data);
}
bool event::signalled()
{
int active;
sem_getvalue((sem_t*)this->data, &active);
return (active>0);
}
multievent::multievent()
{
this->data=malloc(sizeof(sem_t));
sem_init((sem_t*)this->data, 0, 0);
}
multievent::~multievent()
{
sem_destroy((sem_t*)this->data);
free(this->data);
}
void multievent::signal(unsigned int count)
{
while (count--) sem_post((sem_t*)this->data);
}
void multievent::wait(unsigned int count)
{
while (count--) sem_wait((sem_t*)this->data);
}
signed int multievent::count()
{
int active;
sem_getvalue((sem_t*)this->data, &active);
return active;
}
uintptr_t thread_get_id()
{
//disassembly:
//jmpq 0x400500 <pthread_self@plt>
//jmpq *0x200b22(%rip) # 0x601028 <[email protected]>
//mov %fs:0x10,%rax
//retq
//(it's some big mess the first time, apparently the dependency is dynamically loaded)
return pthread_self();
}
////pthread doesn't seem to contain anything like this, but gcc is the only supported compiler here, so I can use its builtins.
////or if I get any non-gcc compilers, I can throw in the C++11 threads. That's why these builtins exist, anyways.
////for Clang, if these GCC builtins aren't supported (most are), http://clang.llvm.org/docs/LanguageExtensions.html#c11-atomic-builtins
//#if __GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__*1 >= 40700
////https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/_005f_005fatomic-Builtins.html
//uint32_t lock_incr(uint32_t * val) { return __atomic_add_fetch(val, 1, __ATOMIC_ACQ_REL); }
//uint32_t lock_decr(uint32_t * val) { return __atomic_sub_fetch(val, 1, __ATOMIC_ACQ_REL); }
//uint32_t lock_read(uint32_t * val) { return __atomic_load_n(val, __ATOMIC_ACQUIRE); }
//
//void* lock_read_i(void* * val) { return __atomic_load_n(val, __ATOMIC_ACQUIRE); }
//void lock_write_i(void** val, void* newval) { return __atomic_store_n(val, newval, __ATOMIC_RELEASE); }
////there is a modern version of this, but it adds another move instruction for whatever reason and otherwise gives the same binary.
//void* lock_write_eq_i(void** val, void* old, void* newval) { return __sync_val_compare_and_swap(val, old, newval); }
////void* lock_write_eq_i(void** val, void* old, void* newval)
////{
//// __atomic_compare_exchange_n(val, &old, newval, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE);
//// return old;
////}
//void* lock_xchg_i(void** val, void* newval) { return __atomic_exchange_n(val, newval, __ATOMIC_ACQ_REL); }
//#else
////https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html
//uint32_t lock_incr(uint32_t * val) { return __sync_add_and_fetch(val, 1); }
//uint32_t lock_decr(uint32_t * val) { return __sync_sub_and_fetch(val, 1); }
//uint32_t lock_read(uint32_t * val) { return __sync_val_compare_and_swap(val, 0, 0); }
//
//inline void* lock_read_i(void* * val) { return __sync_val_compare_and_swap(val, 0, 0); }
//void lock_write_i(void** val, void* newval) { *val=newval; __sync_synchronize(); }
//void* lock_write_eq_i(void** val, void* old, void* newval) { return __sync_val_compare_and_swap(val, old, newval); }
//
////no such thing - emulate it
//void* lock_xchg_i(void** val, void* newval)
//{
// void* prev=lock_read(val);
// while (true)
// {
// void* prev2=lock_write_eq(val, prev, newval);
// if (prev==prev2) break;
// else prev=prev2;
// }
//}
//#endif
#endif