| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#include "pdlcore.h" |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
/* Variable storing the pthread ID for the main PDL thread. |
|
4
|
|
|
|
|
|
|
* This is used to tell if we are in the main pthread, or in one of |
|
5
|
|
|
|
|
|
|
* the pthreads spawned for PDL processing |
|
6
|
|
|
|
|
|
|
* This is only used when compiled with pthreads. |
|
7
|
|
|
|
|
|
|
*/ |
|
8
|
|
|
|
|
|
|
#ifdef PDL_PTHREAD |
|
9
|
|
|
|
|
|
|
static pthread_t pdl_main_pthreadID; |
|
10
|
|
|
|
|
|
|
static int done_pdl_main_pthreadID_init = 0; |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
/* deferred error messages are stored here. We can only barf/warn from the main |
|
13
|
|
|
|
|
|
|
* thread, so worker threads complain here and the complaints are printed out |
|
14
|
|
|
|
|
|
|
* altogether later |
|
15
|
|
|
|
|
|
|
*/ |
|
16
|
|
|
|
|
|
|
static char* pdl_pthread_barf_msgs = NULL; |
|
17
|
|
|
|
|
|
|
static size_t pdl_pthread_barf_msgs_len = 0; |
|
18
|
|
|
|
|
|
|
static char* pdl_pthread_warn_msgs = NULL; |
|
19
|
|
|
|
|
|
|
static size_t pdl_pthread_warn_msgs_len = 0; |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
#endif |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
/* Singly linked list */ |
|
25
|
|
|
|
|
|
|
/* Note that this zeroes ->next!) */ |
|
26
|
|
|
|
|
|
|
|
|
27
|
90
|
|
|
|
|
|
void pdl__magic_add(pdl *it,pdl_magic *mag) |
|
28
|
|
|
|
|
|
|
{ |
|
29
|
90
|
|
|
|
|
|
pdl_magic **foo = (pdl_magic **)(&(it->magic)); |
|
30
|
90
|
50
|
|
|
|
|
while(*foo) { |
|
31
|
0
|
|
|
|
|
|
foo = &((*foo)->next); |
|
32
|
|
|
|
|
|
|
} |
|
33
|
90
|
|
|
|
|
|
(*foo) = mag; |
|
34
|
90
|
|
|
|
|
|
mag->next = NULL; |
|
35
|
90
|
|
|
|
|
|
} |
|
36
|
|
|
|
|
|
|
|
|
37
|
25
|
|
|
|
|
|
pdl_error pdl__magic_rm(pdl *it,pdl_magic *mag) |
|
38
|
|
|
|
|
|
|
{ |
|
39
|
25
|
|
|
|
|
|
pdl_error PDL_err = {0, NULL, 0}; |
|
40
|
25
|
|
|
|
|
|
pdl_magic **foo = (pdl_magic **)(&(it->magic)); |
|
41
|
25
|
|
|
|
|
|
int found = 0; |
|
42
|
50
|
100
|
|
|
|
|
while(*foo) { |
|
43
|
25
|
50
|
|
|
|
|
if(*foo == mag) { |
|
44
|
25
|
|
|
|
|
|
*foo = (*foo)->next; |
|
45
|
25
|
|
|
|
|
|
found = 1; |
|
46
|
|
|
|
|
|
|
} |
|
47
|
|
|
|
|
|
|
else{ |
|
48
|
0
|
|
|
|
|
|
foo = &((*foo)->next); |
|
49
|
|
|
|
|
|
|
} |
|
50
|
|
|
|
|
|
|
} |
|
51
|
25
|
50
|
|
|
|
|
if( !found ){ |
|
52
|
0
|
|
|
|
|
|
return pdl_make_error_simple(PDL_EUSERERROR, "PDL:Magic not found: Internal error\n"); |
|
53
|
|
|
|
|
|
|
} |
|
54
|
25
|
|
|
|
|
|
return PDL_err; |
|
55
|
|
|
|
|
|
|
} |
|
56
|
|
|
|
|
|
|
|
|
57
|
65
|
|
|
|
|
|
void pdl__magic_free(pdl *it) |
|
58
|
|
|
|
|
|
|
{ |
|
59
|
65
|
50
|
|
|
|
|
if (pdl__ismagic(it) && !pdl__magic_isundestroyable(it)) { |
|
|
|
50
|
|
|
|
|
|
|
60
|
65
|
|
|
|
|
|
pdl_magic *foo = (pdl_magic *)(it->magic); |
|
61
|
130
|
100
|
|
|
|
|
while(foo) { |
|
62
|
65
|
|
|
|
|
|
pdl_magic *next = foo->next; |
|
63
|
65
|
|
|
|
|
|
free(foo); |
|
64
|
65
|
|
|
|
|
|
foo = next; |
|
65
|
|
|
|
|
|
|
} |
|
66
|
|
|
|
|
|
|
} |
|
67
|
65
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
/* Test for undestroyability */ |
|
70
|
|
|
|
|
|
|
|
|
71
|
116522
|
|
|
|
|
|
int pdl__magic_isundestroyable(pdl *it) |
|
72
|
|
|
|
|
|
|
{ |
|
73
|
116522
|
|
|
|
|
|
pdl_magic **foo = (pdl_magic **)(&(it->magic)); |
|
74
|
116652
|
100
|
|
|
|
|
while(*foo) { |
|
75
|
130
|
50
|
|
|
|
|
if((*foo)->what & PDL_MAGIC_UNDESTROYABLE) {return 1;} |
|
76
|
130
|
|
|
|
|
|
foo = &((*foo)->next); |
|
77
|
|
|
|
|
|
|
} |
|
78
|
116522
|
|
|
|
|
|
return 0; |
|
79
|
|
|
|
|
|
|
} |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
/* Call magics */ |
|
82
|
|
|
|
|
|
|
|
|
83
|
66
|
|
|
|
|
|
void *pdl__call_magic(pdl *it,int which) |
|
84
|
|
|
|
|
|
|
{ |
|
85
|
66
|
|
|
|
|
|
void *ret = NULL; |
|
86
|
66
|
|
|
|
|
|
pdl_magic **foo = (pdl_magic **)(&(it->magic)); |
|
87
|
132
|
100
|
|
|
|
|
while(*foo) { |
|
88
|
66
|
50
|
|
|
|
|
if((*foo)->what & which) { |
|
89
|
0
|
0
|
|
|
|
|
if((*foo)->what & PDL_MAGIC_DELAYED) |
|
90
|
0
|
|
|
|
|
|
pdl_add_delayed_magic(*foo); |
|
91
|
|
|
|
|
|
|
else |
|
92
|
0
|
|
|
|
|
|
ret = (*foo)->vtable->cast(*foo); |
|
93
|
|
|
|
|
|
|
/* Cast spell */ |
|
94
|
|
|
|
|
|
|
} |
|
95
|
66
|
|
|
|
|
|
foo = &((*foo)->next); |
|
96
|
|
|
|
|
|
|
} |
|
97
|
66
|
|
|
|
|
|
return ret; |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
/* XXX FINDS ONLY FIRST */ |
|
101
|
3347
|
|
|
|
|
|
pdl_magic *pdl__find_magic(pdl *it, int which) |
|
102
|
|
|
|
|
|
|
{ |
|
103
|
3347
|
|
|
|
|
|
pdl_magic **foo = (pdl_magic **)(&(it->magic)); |
|
104
|
3347
|
100
|
|
|
|
|
while(*foo) { |
|
105
|
3346
|
50
|
|
|
|
|
if((*foo)->what & which) { |
|
106
|
3346
|
|
|
|
|
|
return *foo; |
|
107
|
|
|
|
|
|
|
} |
|
108
|
0
|
|
|
|
|
|
foo = &((*foo)->next); |
|
109
|
|
|
|
|
|
|
} |
|
110
|
1
|
|
|
|
|
|
return NULL; |
|
111
|
|
|
|
|
|
|
} |
|
112
|
|
|
|
|
|
|
|
|
113
|
0
|
|
|
|
|
|
pdl_magic *pdl__print_magic(pdl *it) |
|
114
|
|
|
|
|
|
|
{ |
|
115
|
0
|
|
|
|
|
|
pdl_magic **foo = (pdl_magic **)(&(it->magic)); |
|
116
|
0
|
0
|
|
|
|
|
while(*foo) { |
|
117
|
0
|
|
|
|
|
|
printf("Magic %p\ttype: ",*foo); |
|
118
|
0
|
0
|
|
|
|
|
if((*foo)->what & PDL_MAGIC_MARKCHANGED) |
|
119
|
0
|
|
|
|
|
|
printf("PDL_MAGIC_MARKCHANGED"); |
|
120
|
0
|
0
|
|
|
|
|
else if ((*foo)->what & PDL_MAGIC_THREADING) |
|
121
|
0
|
|
|
|
|
|
printf("PDL_MAGIC_THREADING"); |
|
122
|
|
|
|
|
|
|
else |
|
123
|
0
|
|
|
|
|
|
printf("UNKNOWN"); |
|
124
|
0
|
0
|
|
|
|
|
if ((*foo)->what & (PDL_MAGIC_DELAYED|PDL_MAGIC_UNDESTROYABLE)) |
|
125
|
|
|
|
|
|
|
{ |
|
126
|
0
|
|
|
|
|
|
printf(" qualifier(s): "); |
|
127
|
0
|
0
|
|
|
|
|
if ((*foo)->what & PDL_MAGIC_DELAYED) |
|
128
|
0
|
|
|
|
|
|
printf(" PDL_MAGIC_DELAYED"); |
|
129
|
0
|
0
|
|
|
|
|
if ((*foo)->what & PDL_MAGIC_UNDESTROYABLE) |
|
130
|
0
|
|
|
|
|
|
printf(" PDL_MAGIC_UNDESTROYABLE"); |
|
131
|
|
|
|
|
|
|
} |
|
132
|
0
|
|
|
|
|
|
printf("\n"); |
|
133
|
0
|
|
|
|
|
|
foo = &((*foo)->next); |
|
134
|
|
|
|
|
|
|
} |
|
135
|
0
|
|
|
|
|
|
return NULL; |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
|
|
139
|
112751
|
|
|
|
|
|
int pdl__ismagic(pdl *it) |
|
140
|
|
|
|
|
|
|
{ |
|
141
|
112751
|
|
|
|
|
|
return (it->magic != 0); |
|
142
|
|
|
|
|
|
|
} |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
static pdl_magic **delayed=NULL; |
|
145
|
|
|
|
|
|
|
static PDL_Indx ndelayed = 0; |
|
146
|
0
|
|
|
|
|
|
void pdl_add_delayed_magic(pdl_magic *mag) { |
|
147
|
|
|
|
|
|
|
/* FIXME: Common realloc mistake: 'delayed' nulled but not freed upon failure */ |
|
148
|
0
|
|
|
|
|
|
delayed = realloc(delayed,sizeof(*delayed)*++ndelayed); |
|
149
|
0
|
|
|
|
|
|
delayed[ndelayed-1] = mag; |
|
150
|
0
|
|
|
|
|
|
} |
|
151
|
0
|
|
|
|
|
|
void pdl_run_delayed_magic(void) { |
|
152
|
|
|
|
|
|
|
PDL_Indx i; |
|
153
|
0
|
|
|
|
|
|
pdl_magic **oldd = delayed; /* In case someone makes new delayed stuff */ |
|
154
|
0
|
|
|
|
|
|
PDL_Indx nold = ndelayed; |
|
155
|
0
|
|
|
|
|
|
delayed = NULL; |
|
156
|
0
|
|
|
|
|
|
ndelayed = 0; |
|
157
|
0
|
0
|
|
|
|
|
for(i=0; i
|
|
158
|
0
|
|
|
|
|
|
oldd[i]->vtable->cast(oldd[i]); |
|
159
|
|
|
|
|
|
|
} |
|
160
|
0
|
|
|
|
|
|
free(oldd); |
|
161
|
0
|
|
|
|
|
|
} |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
/**************** |
|
164
|
|
|
|
|
|
|
* |
|
165
|
|
|
|
|
|
|
* ->bind - magic |
|
166
|
|
|
|
|
|
|
*/ |
|
167
|
0
|
|
|
|
|
|
void *svmagic_cast(pdl_magic *mag) |
|
168
|
|
|
|
|
|
|
{ |
|
169
|
0
|
|
|
|
|
|
pdl_magic_perlfunc *magp = (pdl_magic_perlfunc *)mag; |
|
170
|
0
|
|
|
|
|
|
dSP; |
|
171
|
0
|
|
|
|
|
|
ENTER; SAVETMPS; |
|
172
|
0
|
0
|
|
|
|
|
PUSHMARK(SP); |
|
173
|
0
|
|
|
|
|
|
perl_call_sv(magp->sv, G_DISCARD | G_NOARGS); |
|
174
|
0
|
0
|
|
|
|
|
FREETMPS; LEAVE; |
|
175
|
0
|
|
|
|
|
|
return NULL; |
|
176
|
|
|
|
|
|
|
} |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
static pdl_magic_vtable svmagic_vtable = { |
|
179
|
|
|
|
|
|
|
svmagic_cast, |
|
180
|
|
|
|
|
|
|
NULL |
|
181
|
|
|
|
|
|
|
}; |
|
182
|
|
|
|
|
|
|
|
|
183
|
0
|
|
|
|
|
|
pdl_magic *pdl_add_svmagic(pdl *it,SV *func) |
|
184
|
|
|
|
|
|
|
{ |
|
185
|
|
|
|
|
|
|
AV *av; |
|
186
|
0
|
|
|
|
|
|
pdl_magic_perlfunc *ptr = malloc(sizeof(pdl_magic_perlfunc)); |
|
187
|
0
|
0
|
|
|
|
|
if (!ptr) return NULL; |
|
188
|
0
|
|
|
|
|
|
ptr->what = PDL_MAGIC_MARKCHANGED | PDL_MAGIC_DELAYED; |
|
189
|
0
|
|
|
|
|
|
ptr->vtable = &svmagic_vtable; |
|
190
|
0
|
|
|
|
|
|
ptr->sv = newSVsv(func); |
|
191
|
0
|
|
|
|
|
|
ptr->pdl = it; |
|
192
|
0
|
|
|
|
|
|
ptr->next = NULL; |
|
193
|
0
|
|
|
|
|
|
pdl__magic_add(it,(pdl_magic *)ptr); |
|
194
|
0
|
0
|
|
|
|
|
if(it->state & PDL_ANYCHANGED) |
|
195
|
0
|
|
|
|
|
|
pdl_add_delayed_magic((pdl_magic *)ptr); |
|
196
|
|
|
|
|
|
|
/* In order to have our SV destroyed in time for the interpreter, */ |
|
197
|
|
|
|
|
|
|
/* XXX Work this out not to memleak */ |
|
198
|
0
|
|
|
|
|
|
av = perl_get_av("PDL::disposable_svmagics",TRUE); |
|
199
|
0
|
|
|
|
|
|
av_push(av,ptr->sv); |
|
200
|
0
|
|
|
|
|
|
return (pdl_magic *)ptr; |
|
201
|
|
|
|
|
|
|
} |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
#ifdef PDL_PTHREAD |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
/************** |
|
206
|
|
|
|
|
|
|
* |
|
207
|
|
|
|
|
|
|
* pthreads |
|
208
|
|
|
|
|
|
|
* |
|
209
|
|
|
|
|
|
|
*/ |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
typedef struct ptarg { |
|
212
|
|
|
|
|
|
|
pdl_magic_pthread *mag; |
|
213
|
|
|
|
|
|
|
pdl_error (*func)(pdl_trans *); |
|
214
|
|
|
|
|
|
|
pdl_trans *t; |
|
215
|
|
|
|
|
|
|
int no; |
|
216
|
|
|
|
|
|
|
pdl_error error_return; |
|
217
|
|
|
|
|
|
|
} ptarg; |
|
218
|
|
|
|
|
|
|
|
|
219
|
1
|
|
|
|
|
|
int pdl_pthreads_enabled(void) {return 1;} |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
|
|
222
|
572
|
|
|
|
|
|
static void *pthread_perform(void *vp) { |
|
223
|
572
|
|
|
|
|
|
struct ptarg *p = (ptarg *)vp; |
|
224
|
572
|
50
|
|
|
|
|
PDLDEBUG_f(printf("STARTING THREAD %d (%lu)\n",p->no, (long unsigned)pthread_self())); |
|
225
|
572
|
|
|
|
|
|
pthread_setspecific(p->mag->key,(void *)&(p->no)); |
|
226
|
|
|
|
|
|
|
int oldtype; /* don't care but must supply */ |
|
227
|
572
|
|
|
|
|
|
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); |
|
228
|
572
|
|
|
|
|
|
p->error_return = (p->func)(p->t); |
|
229
|
572
|
50
|
|
|
|
|
PDLDEBUG_f(printf("ENDING THREAD %d (%lu)\n",p->no, (long unsigned)pthread_self())); |
|
230
|
572
|
|
|
|
|
|
return NULL; |
|
231
|
|
|
|
|
|
|
} |
|
232
|
|
|
|
|
|
|
|
|
233
|
133
|
|
|
|
|
|
int pdl_magic_thread_nthreads(pdl *it, PDL_Indx *nthdim) { |
|
234
|
133
|
|
|
|
|
|
pdl_magic_pthread *ptr = (pdl_magic_pthread *)pdl__find_magic(it, PDL_MAGIC_THREADING); |
|
235
|
133
|
50
|
|
|
|
|
if(!ptr) return 0; |
|
236
|
133
|
100
|
|
|
|
|
if (nthdim) *nthdim = ptr->nthdim; |
|
237
|
133
|
|
|
|
|
|
return ptr->nthreads; |
|
238
|
|
|
|
|
|
|
} |
|
239
|
|
|
|
|
|
|
|
|
240
|
3073
|
|
|
|
|
|
int pdl_magic_get_thread(pdl *it) { |
|
241
|
3073
|
|
|
|
|
|
pdl_magic_pthread *ptr = (pdl_magic_pthread *)pdl__find_magic(it, PDL_MAGIC_THREADING); |
|
242
|
3073
|
50
|
|
|
|
|
if(!ptr) return -1; |
|
243
|
3073
|
|
|
|
|
|
int *p = (int*)pthread_getspecific(ptr->key); |
|
244
|
3073
|
50
|
|
|
|
|
if(!p) return -1; |
|
245
|
3073
|
|
|
|
|
|
return *p; |
|
246
|
|
|
|
|
|
|
} |
|
247
|
|
|
|
|
|
|
|
|
248
|
115
|
|
|
|
|
|
pdl_error pdl_magic_thread_cast(pdl *it,pdl_error (*func)(pdl_trans *),pdl_trans *t, pdl_broadcast *broadcast) { |
|
249
|
115
|
|
|
|
|
|
pdl_error PDL_err = {0, NULL, 0}; |
|
250
|
115
|
50
|
|
|
|
|
PDL_BRC_CHKMAGIC(broadcast); |
|
|
|
0
|
|
|
|
|
|
|
251
|
115
|
|
|
|
|
|
int clearMagic = 0; /* Flag = 1 if we are temporarily creating pthreading magic in the |
|
252
|
|
|
|
|
|
|
supplied pdl. */ |
|
253
|
115
|
|
|
|
|
|
pdl_magic_pthread *ptr = (pdl_magic_pthread *)pdl__find_magic(it, PDL_MAGIC_THREADING); |
|
254
|
115
|
50
|
|
|
|
|
if(!ptr) { |
|
255
|
|
|
|
|
|
|
/* Magic doesn't exist, create it |
|
256
|
|
|
|
|
|
|
Probably was deleted before the transformation performed, due to |
|
257
|
|
|
|
|
|
|
pdl lazy evaluation. |
|
258
|
|
|
|
|
|
|
*/ |
|
259
|
|
|
|
|
|
|
|
|
260
|
0
|
0
|
|
|
|
|
PDL_RETERROR(PDL_err, pdl_add_threading_magic(it, broadcast->mag_nth, broadcast->mag_nthr)); |
|
261
|
0
|
|
|
|
|
|
clearMagic = 1; /* Set flag to delete magic later */ |
|
262
|
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
/* Try to get magic again */ |
|
264
|
0
|
|
|
|
|
|
ptr = (pdl_magic_pthread *)pdl__find_magic(it, PDL_MAGIC_THREADING); |
|
265
|
|
|
|
|
|
|
|
|
266
|
0
|
0
|
|
|
|
|
if(!ptr) {return pdl_make_error_simple(PDL_EFATAL, "Invalid pdl_magic_thread_cast!");} |
|
267
|
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
} |
|
269
|
|
|
|
|
|
|
|
|
270
|
115
|
|
|
|
|
|
pthread_t tp[broadcast->mag_nthr]; |
|
271
|
115
|
|
|
|
|
|
ptarg tparg[broadcast->mag_nthr]; |
|
272
|
115
|
|
|
|
|
|
pthread_key_create(&(ptr->key),NULL); |
|
273
|
|
|
|
|
|
|
/* Get the pthread ID of this main thread we are in. |
|
274
|
|
|
|
|
|
|
* Any barf, warn, etc calls in the spawned pthreads can use this |
|
275
|
|
|
|
|
|
|
* to tell if it's a spawned pthread |
|
276
|
|
|
|
|
|
|
*/ |
|
277
|
115
|
|
|
|
|
|
pdl_main_pthreadID = pthread_self(); |
|
278
|
115
|
|
|
|
|
|
done_pdl_main_pthreadID_init = 1; |
|
279
|
|
|
|
|
|
|
|
|
280
|
115
|
50
|
|
|
|
|
PDLDEBUG_f(printf("CREATING THREADS, ME: TBD, key: %ld\n", (unsigned long)(ptr->key))); |
|
281
|
115
|
|
|
|
|
|
PDL_Indx i, last_pthread = -1; |
|
282
|
687
|
100
|
|
|
|
|
for(i=0; imag_nthr; i++) { |
|
283
|
572
|
|
|
|
|
|
tparg[i].mag = ptr; |
|
284
|
572
|
|
|
|
|
|
tparg[i].func = func; |
|
285
|
572
|
|
|
|
|
|
tparg[i].t = t; |
|
286
|
572
|
|
|
|
|
|
tparg[i].no = i; |
|
287
|
572
|
|
|
|
|
|
tparg[i].error_return = PDL_err; |
|
288
|
572
|
50
|
|
|
|
|
if (pthread_create(tp+i, NULL, pthread_perform, tparg+i)) |
|
289
|
0
|
|
|
|
|
|
break; |
|
290
|
572
|
|
|
|
|
|
last_pthread = i; |
|
291
|
|
|
|
|
|
|
} |
|
292
|
115
|
50
|
|
|
|
|
if (last_pthread < broadcast->mag_nthr-1) { |
|
293
|
|
|
|
|
|
|
/* went wrong, cancel ones that started */ |
|
294
|
0
|
0
|
|
|
|
|
for (i=0; i <= last_pthread; i++) |
|
295
|
0
|
|
|
|
|
|
pthread_cancel(tp[i]); |
|
296
|
|
|
|
|
|
|
} |
|
297
|
|
|
|
|
|
|
|
|
298
|
115
|
50
|
|
|
|
|
PDLDEBUG_f(printf("JOINING THREADS, ME: TBD, key: %ld\n", (unsigned long)(ptr->key))); |
|
299
|
687
|
100
|
|
|
|
|
for(i=0; i<=last_pthread; i++) { |
|
300
|
572
|
|
|
|
|
|
pthread_join(tp[i], NULL); |
|
301
|
|
|
|
|
|
|
} |
|
302
|
115
|
50
|
|
|
|
|
PDLDEBUG_f(printf("FINISHED THREADS, ME: TBD, key: %ld\n", (unsigned long)(ptr->key))); |
|
303
|
|
|
|
|
|
|
|
|
304
|
115
|
|
|
|
|
|
pthread_key_delete((ptr->key)); |
|
305
|
115
|
|
|
|
|
|
done_pdl_main_pthreadID_init = 0; |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
/* Remove pthread magic if we created in this function */ |
|
308
|
115
|
50
|
|
|
|
|
if( clearMagic ){ |
|
309
|
0
|
0
|
|
|
|
|
PDL_RETERROR(PDL_err, pdl_add_threading_magic(it, -1, -1)); |
|
310
|
|
|
|
|
|
|
} |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
#define handle_deferred_errors(type, action) \ |
|
313
|
|
|
|
|
|
|
do{ \ |
|
314
|
|
|
|
|
|
|
if(pdl_pthread_##type##_msgs_len != 0) \ |
|
315
|
|
|
|
|
|
|
{ \ |
|
316
|
|
|
|
|
|
|
pdl_pthread_##type##_msgs_len = 0; \ |
|
317
|
|
|
|
|
|
|
action; \ |
|
318
|
|
|
|
|
|
|
free(pdl_pthread_##type##_msgs); \ |
|
319
|
|
|
|
|
|
|
pdl_pthread_##type##_msgs = NULL; \ |
|
320
|
|
|
|
|
|
|
} \ |
|
321
|
|
|
|
|
|
|
} while(0) |
|
322
|
|
|
|
|
|
|
|
|
323
|
115
|
50
|
|
|
|
|
handle_deferred_errors(warn, pdl_pdl_warn("%s", pdl_pthread_warn_msgs)); |
|
324
|
115
|
50
|
|
|
|
|
if (last_pthread < broadcast->mag_nthr-1) |
|
325
|
0
|
|
|
|
|
|
return pdl_make_error_simple(PDL_EFATAL, "Failed to create at least one thread, aborting"); |
|
326
|
115
|
50
|
|
|
|
|
handle_deferred_errors(barf, PDL_err = pdl_error_accumulate(PDL_err, pdl_make_error(PDL_EUSERERROR, "%s", pdl_pthread_barf_msgs))); |
|
327
|
687
|
100
|
|
|
|
|
for(i=0; imag_nthr; i++) { |
|
328
|
572
|
|
|
|
|
|
PDL_err = pdl_error_accumulate(PDL_err, tparg[i].error_return); |
|
329
|
|
|
|
|
|
|
} |
|
330
|
115
|
|
|
|
|
|
return PDL_err; |
|
331
|
|
|
|
|
|
|
} |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
/* Function to remove threading magic (added by pdl_add_threading_magic) */ |
|
334
|
26
|
|
|
|
|
|
pdl_error pdl_rm_threading_magic(pdl *it) |
|
335
|
|
|
|
|
|
|
{ |
|
336
|
26
|
|
|
|
|
|
pdl_error PDL_err = {0, NULL, 0}; |
|
337
|
26
|
|
|
|
|
|
pdl_magic_pthread *ptr = (pdl_magic_pthread *)pdl__find_magic(it, PDL_MAGIC_THREADING); |
|
338
|
|
|
|
|
|
|
/* Don't do anything if threading magic not found */ |
|
339
|
26
|
100
|
|
|
|
|
if( !ptr) return PDL_err; |
|
340
|
|
|
|
|
|
|
/* Remove magic */ |
|
341
|
25
|
50
|
|
|
|
|
PDL_RETERROR(PDL_err, pdl__magic_rm(it, (pdl_magic *) ptr)); |
|
342
|
|
|
|
|
|
|
/* Free magic */ |
|
343
|
25
|
|
|
|
|
|
free( ptr ); |
|
344
|
25
|
|
|
|
|
|
return PDL_err; |
|
345
|
|
|
|
|
|
|
} |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
/* Function to add threading magic (i.e. identify which PDL dimension should |
|
348
|
|
|
|
|
|
|
be pthreaded and how many pthreads to create |
|
349
|
|
|
|
|
|
|
Note: If nthdim and nthreads = -1 then any pthreading magic is removed */ |
|
350
|
116
|
|
|
|
|
|
pdl_error pdl_add_threading_magic(pdl *it,PDL_Indx nthdim,PDL_Indx nthreads) |
|
351
|
|
|
|
|
|
|
{ |
|
352
|
116
|
|
|
|
|
|
pdl_error PDL_err = {0, NULL, 0}; |
|
353
|
|
|
|
|
|
|
pdl_magic_pthread *ptr; |
|
354
|
|
|
|
|
|
|
/* Remove threading magic if called with parms -1, -1 */ |
|
355
|
116
|
100
|
|
|
|
|
if( (nthdim == -1) && ( nthreads == -1 ) ){ |
|
|
|
50
|
|
|
|
|
|
|
356
|
26
|
50
|
|
|
|
|
PDL_RETERROR(PDL_err, pdl_rm_threading_magic(it)); |
|
357
|
26
|
|
|
|
|
|
return PDL_err; |
|
358
|
|
|
|
|
|
|
} |
|
359
|
90
|
|
|
|
|
|
ptr = malloc(sizeof(pdl_magic_pthread)); |
|
360
|
90
|
50
|
|
|
|
|
if (!ptr) return pdl_make_error_simple(PDL_EFATAL, "Out of memory"); |
|
361
|
90
|
|
|
|
|
|
ptr->what = PDL_MAGIC_THREADING; |
|
362
|
90
|
|
|
|
|
|
ptr->vtable = NULL; |
|
363
|
90
|
|
|
|
|
|
ptr->next = NULL; |
|
364
|
90
|
|
|
|
|
|
ptr->nthdim = nthdim; |
|
365
|
90
|
|
|
|
|
|
ptr->nthreads = nthreads; |
|
366
|
90
|
|
|
|
|
|
pdl__magic_add(it,(pdl_magic *)ptr); |
|
367
|
90
|
|
|
|
|
|
return PDL_err; |
|
368
|
|
|
|
|
|
|
} |
|
369
|
|
|
|
|
|
|
|
|
370
|
280
|
|
|
|
|
|
char pdl_pthread_main_thread(void) { |
|
371
|
280
|
100
|
|
|
|
|
return !done_pdl_main_pthreadID_init || pthread_equal( pdl_main_pthreadID, pthread_self() ); |
|
|
|
50
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
} |
|
373
|
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
// Barf/warn function for deferred barf message handling during pthreading We |
|
375
|
|
|
|
|
|
|
// can't barf/warn during pthreading, because perl-level code isn't |
|
376
|
|
|
|
|
|
|
// threadsafe. This routine does nothing if we're in the main thread (allowing |
|
377
|
|
|
|
|
|
|
// the caller to barf normally, since there are not threading issues then). If |
|
378
|
|
|
|
|
|
|
// we're in a worker thread, this routine stores the message for main-thread |
|
379
|
|
|
|
|
|
|
// reporting later |
|
380
|
165
|
|
|
|
|
|
int pdl_pthread_barf_or_warn(const char* pat, int iswarn, va_list *args) |
|
381
|
|
|
|
|
|
|
{ |
|
382
|
|
|
|
|
|
|
char** msgs; |
|
383
|
|
|
|
|
|
|
size_t* len; |
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
/* Don't do anything if we are in the main pthread */ |
|
386
|
165
|
50
|
|
|
|
|
if (pdl_pthread_main_thread()) return 0; |
|
387
|
|
|
|
|
|
|
|
|
388
|
0
|
0
|
|
|
|
|
if(iswarn) |
|
389
|
|
|
|
|
|
|
{ |
|
390
|
0
|
|
|
|
|
|
msgs = &pdl_pthread_warn_msgs; |
|
391
|
0
|
|
|
|
|
|
len = &pdl_pthread_warn_msgs_len; |
|
392
|
|
|
|
|
|
|
} |
|
393
|
|
|
|
|
|
|
else |
|
394
|
|
|
|
|
|
|
{ |
|
395
|
0
|
|
|
|
|
|
msgs = &pdl_pthread_barf_msgs; |
|
396
|
0
|
|
|
|
|
|
len = &pdl_pthread_barf_msgs_len; |
|
397
|
|
|
|
|
|
|
} |
|
398
|
|
|
|
|
|
|
|
|
399
|
0
|
|
|
|
|
|
size_t extralen = vsnprintf(NULL, 0, pat, *args); |
|
400
|
|
|
|
|
|
|
// add the new complaint to the list |
|
401
|
0
|
|
|
|
|
|
pdl_pthread_realloc_vsnprintf(msgs, len, extralen, pat, args, 1); |
|
402
|
|
|
|
|
|
|
|
|
403
|
0
|
0
|
|
|
|
|
if(iswarn) |
|
404
|
|
|
|
|
|
|
{ |
|
405
|
|
|
|
|
|
|
/* Return 1, indicating we have handled the warn messages */ |
|
406
|
0
|
|
|
|
|
|
return(1); |
|
407
|
|
|
|
|
|
|
} |
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
/* Exit the current pthread. Since this was a barf call, and we should be halting execution */ |
|
410
|
0
|
|
|
|
|
|
pthread_exit(NULL); |
|
411
|
|
|
|
|
|
|
return 0; |
|
412
|
|
|
|
|
|
|
} |
|
413
|
|
|
|
|
|
|
|
|
414
|
1
|
|
|
|
|
|
void pdl_pthread_realloc_vsnprintf(char **p, size_t *len, size_t extralen, const char *pat, va_list *args, char add_newline) { |
|
415
|
|
|
|
|
|
|
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; |
|
416
|
1
|
|
|
|
|
|
pthread_mutex_lock( &mutex ); |
|
417
|
|
|
|
|
|
|
/* (For windows, we first #undef realloc |
|
418
|
|
|
|
|
|
|
so that the system realloc function is used instead of the PerlMem_realloc |
|
419
|
|
|
|
|
|
|
macro. This currently works fine, though could conceivably require some |
|
420
|
|
|
|
|
|
|
tweaking in the future if it's found to cause any problem.) */ |
|
421
|
|
|
|
|
|
|
#ifdef WIN32 |
|
422
|
|
|
|
|
|
|
#undef realloc |
|
423
|
|
|
|
|
|
|
#endif |
|
424
|
1
|
50
|
|
|
|
|
if (add_newline) extralen += 1; |
|
425
|
1
|
|
|
|
|
|
extralen += 1; /* +1 for '\0' at end */ |
|
426
|
1
|
|
|
|
|
|
*p = realloc(*p, *len + extralen); |
|
427
|
1
|
|
|
|
|
|
vsnprintf(*p + *len, extralen, pat, *args); |
|
428
|
1
|
|
|
|
|
|
*len += extralen; /* update the length-so-far, includes '\0' */ |
|
429
|
1
|
50
|
|
|
|
|
if (add_newline) (*p)[*len-2] = '\n'; |
|
430
|
1
|
|
|
|
|
|
(*p)[*len-1] = '\0'; |
|
431
|
1
|
|
|
|
|
|
pthread_mutex_unlock( &mutex ); |
|
432
|
1
|
|
|
|
|
|
} |
|
433
|
|
|
|
|
|
|
|
|
434
|
1
|
|
|
|
|
|
void pdl_pthread_free(void *p) { |
|
435
|
|
|
|
|
|
|
#ifdef WIN32 /* same reasons as above */ |
|
436
|
|
|
|
|
|
|
#undef free |
|
437
|
|
|
|
|
|
|
#endif |
|
438
|
|
|
|
|
|
|
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; |
|
439
|
1
|
|
|
|
|
|
pthread_mutex_lock( &mutex ); |
|
440
|
1
|
|
|
|
|
|
free(p); |
|
441
|
1
|
|
|
|
|
|
pthread_mutex_unlock( &mutex ); |
|
442
|
1
|
|
|
|
|
|
} |
|
443
|
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
/* copied from git@github.com:git/git.git 2.34-ish thread-util.c */ |
|
445
|
|
|
|
|
|
|
/* changed GIT_WINDOWS_NATIVE to WIN32 */ |
|
446
|
|
|
|
|
|
|
#if defined(hpux) || defined(__hpux) || defined(_hpux) |
|
447
|
|
|
|
|
|
|
# include |
|
448
|
|
|
|
|
|
|
#endif |
|
449
|
|
|
|
|
|
|
/* |
|
450
|
|
|
|
|
|
|
* By doing this in two steps we can at least get |
|
451
|
|
|
|
|
|
|
* the function to be somewhat coherent, even |
|
452
|
|
|
|
|
|
|
* with this disgusting nest of #ifdefs. |
|
453
|
|
|
|
|
|
|
*/ |
|
454
|
|
|
|
|
|
|
#ifndef _SC_NPROCESSORS_ONLN |
|
455
|
|
|
|
|
|
|
# ifdef _SC_NPROC_ONLN |
|
456
|
|
|
|
|
|
|
# define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN |
|
457
|
|
|
|
|
|
|
# elif defined _SC_CRAY_NCPU |
|
458
|
|
|
|
|
|
|
# define _SC_NPROCESSORS_ONLN _SC_CRAY_NCPU |
|
459
|
|
|
|
|
|
|
# endif |
|
460
|
|
|
|
|
|
|
#endif |
|
461
|
80
|
|
|
|
|
|
int pdl_online_cpus(void) |
|
462
|
|
|
|
|
|
|
{ |
|
463
|
|
|
|
|
|
|
#ifdef WIN32 |
|
464
|
|
|
|
|
|
|
SYSTEM_INFO info; |
|
465
|
|
|
|
|
|
|
GetSystemInfo(&info); |
|
466
|
|
|
|
|
|
|
if ((int)info.dwNumberOfProcessors > 0) |
|
467
|
|
|
|
|
|
|
return (int)info.dwNumberOfProcessors; |
|
468
|
|
|
|
|
|
|
#elif defined(hpux) || defined(__hpux) || defined(_hpux) |
|
469
|
|
|
|
|
|
|
struct pst_dynamic psd; |
|
470
|
|
|
|
|
|
|
if (!pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0)) |
|
471
|
|
|
|
|
|
|
return (int)psd.psd_proc_cnt; |
|
472
|
|
|
|
|
|
|
#elif defined(HAVE_BSD_SYSCTL) && defined(HW_NCPU) |
|
473
|
|
|
|
|
|
|
int mib[2]; |
|
474
|
|
|
|
|
|
|
size_t len; |
|
475
|
|
|
|
|
|
|
int cpucount; |
|
476
|
|
|
|
|
|
|
mib[0] = CTL_HW; |
|
477
|
|
|
|
|
|
|
# ifdef HW_AVAILCPU |
|
478
|
|
|
|
|
|
|
mib[1] = HW_AVAILCPU; |
|
479
|
|
|
|
|
|
|
len = sizeof(cpucount); |
|
480
|
|
|
|
|
|
|
if (!sysctl(mib, 2, &cpucount, &len, NULL, 0)) |
|
481
|
|
|
|
|
|
|
return cpucount; |
|
482
|
|
|
|
|
|
|
# endif /* HW_AVAILCPU */ |
|
483
|
|
|
|
|
|
|
mib[1] = HW_NCPU; |
|
484
|
|
|
|
|
|
|
len = sizeof(cpucount); |
|
485
|
|
|
|
|
|
|
if (!sysctl(mib, 2, &cpucount, &len, NULL, 0)) |
|
486
|
|
|
|
|
|
|
return cpucount; |
|
487
|
|
|
|
|
|
|
#endif /* defined(HAVE_BSD_SYSCTL) && defined(HW_NCPU) */ |
|
488
|
|
|
|
|
|
|
#ifdef _SC_NPROCESSORS_ONLN |
|
489
|
|
|
|
|
|
|
long ncpus; |
|
490
|
80
|
50
|
|
|
|
|
if ((ncpus = (long)sysconf(_SC_NPROCESSORS_ONLN)) > 0) |
|
491
|
80
|
|
|
|
|
|
return (int)ncpus; |
|
492
|
|
|
|
|
|
|
#endif |
|
493
|
0
|
|
|
|
|
|
return 1; |
|
494
|
|
|
|
|
|
|
} |
|
495
|
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
#else |
|
497
|
|
|
|
|
|
|
/* Dummy versions */ |
|
498
|
|
|
|
|
|
|
pdl_error pdl_add_threading_magic(pdl *it,PDL_Indx nthdim,PDL_Indx nthreads) {pdl_error PDL_err = {0,NULL,0}; return PDL_err;} |
|
499
|
|
|
|
|
|
|
char pdl_pthread_main_thread() { return 1; } |
|
500
|
|
|
|
|
|
|
int pdl_magic_get_thread(pdl *it) {return 0;} |
|
501
|
|
|
|
|
|
|
pdl_error pdl_magic_thread_cast(pdl *it,pdl_error (*func)(pdl_trans *),pdl_trans *t, pdl_broadcast *broadcast) {pdl_error PDL_err = {0,NULL,0}; return PDL_err;} |
|
502
|
|
|
|
|
|
|
int pdl_magic_thread_nthreads(pdl *it,PDL_Indx *nthdim) {return 0;} |
|
503
|
|
|
|
|
|
|
int pdl_pthreads_enabled() {return 0;} |
|
504
|
|
|
|
|
|
|
int pdl_pthread_barf_or_warn(const char* pat, int iswarn, va_list *args){ return 0;} |
|
505
|
|
|
|
|
|
|
int pdl_online_cpus() {return 1;} |
|
506
|
|
|
|
|
|
|
#endif |
|
507
|
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
/*************************** |
|
509
|
|
|
|
|
|
|
* |
|
510
|
|
|
|
|
|
|
* Delete magic |
|
511
|
|
|
|
|
|
|
* |
|
512
|
|
|
|
|
|
|
*/ |
|
513
|
|
|
|
|
|
|
|
|
514
|
0
|
|
|
|
|
|
static void *delete_mmapped_cast(pdl_magic *mag) |
|
515
|
|
|
|
|
|
|
{ |
|
516
|
0
|
|
|
|
|
|
pdl_magic_deletedata *magp = (pdl_magic_deletedata *)mag; |
|
517
|
0
|
|
|
|
|
|
magp->func(magp->pdl, magp->param); |
|
518
|
0
|
|
|
|
|
|
return NULL; |
|
519
|
|
|
|
|
|
|
} |
|
520
|
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
struct pdl_magic_vtable deletedatamagic_vtable = { |
|
522
|
|
|
|
|
|
|
delete_mmapped_cast, |
|
523
|
|
|
|
|
|
|
NULL |
|
524
|
|
|
|
|
|
|
}; |
|
525
|
|
|
|
|
|
|
|
|
526
|
0
|
|
|
|
|
|
pdl_error pdl_add_deletedata_magic(pdl *it, void (*func)(pdl *, Size_t param), Size_t param) |
|
527
|
|
|
|
|
|
|
{ |
|
528
|
0
|
|
|
|
|
|
pdl_error PDL_err = {0, NULL, 0}; |
|
529
|
0
|
|
|
|
|
|
pdl_magic_deletedata *ptr = malloc(sizeof(pdl_magic_deletedata)); |
|
530
|
0
|
0
|
|
|
|
|
if (!ptr) return pdl_make_error_simple(PDL_EFATAL, "Out of memory"); |
|
531
|
0
|
|
|
|
|
|
ptr->what = PDL_MAGIC_DELETEDATA; |
|
532
|
0
|
|
|
|
|
|
ptr->vtable = &deletedatamagic_vtable; |
|
533
|
0
|
|
|
|
|
|
ptr->pdl = it; |
|
534
|
0
|
|
|
|
|
|
ptr->func = func; |
|
535
|
0
|
|
|
|
|
|
ptr->param = param; |
|
536
|
0
|
|
|
|
|
|
pdl__magic_add(it, (pdl_magic *)ptr); |
|
537
|
0
|
|
|
|
|
|
return PDL_err; |
|
538
|
|
|
|
|
|
|
} |