1CPOOL(3) Common Library Functions
2CPOOL(3)
3
4
5
6[1mNAME[0m
7 [1mCpool [22m‐ [1mLCG Pool [22minferface
8
9[1mSYNOPSIS[0m
10 [1m#include <Cpool_api.h>[0m
11
12 [1mint Cpool_create(int [4m[22mnbwanted[24m[1m, int *
13[4m[22mnbget[24m[1m);[0m
14
15 [1mint Cpool_assign(int [4m[22mpoolid[24m[1m, void
16*(*[4m[22mstartroutine[24m[1m)(void *), void
17*[4m[22marg[24m[1m,[0m
18 [1mint [4m[22mtimeout[24m[1m);[0m
19
20 [1mint Cpool_next_index(int [4m[22mpoolid[24m[1m);[0m
21
22 [1mint Cpool_next_index_timeout(int [4m[22mpoolid[24m[1m,
23int [4m[22mtimeout[24m[1m);[0m
24
25
26[1mERRORS[0m
27 See [1mCthread [22mcorresponding section.
28
29
30[1mDESCRIPTION[0m
31 [1m(Please read the NOTE section)[0m
32
33 [1mCpool [22mis a layer built upon [1mCthread[22m, the
34[1mLCG Thread [22minterface. It
35 allows the user to create dedicated pools, and then to as‐
36sign to one of
37 them a given routine to execute.
38
39 The created processes or threads will remain alive, unless
40the routines
41 assigned to are crashing, or explicitly calling an exit
42statement, like
43 exit() or pthread_exit().
44
45 Typical use might be writing a server, with a bunch of
46pre‐created pro‐
47 cesses or pools (depending on the environment with
48which [1mCthread [22mhas
49 been compiled), and assign to a given pool a routine with
50the socket
51 file descriptor as argument address.
52
53 In principle [1mCpool [22mshould be compiled with the same
54relevant flags with
55 which [1mCthread [22mhas been.
56
57 [1mint Cpool_create(int [4m[22mnbwanted[24m[1m, int *
58[4m[22mnbget[24m[1m);[0m
59
60 This method is creating a pool of [4mnbwanted[24m process‐
61es or threads. If the
62 second argument, [4mnbget[24m , is not NULL, its loca‐
63tion will contain the
64 number of effectively created threads or processes.
65
66 Return value is the pool ID, a number greater or equal to
67zero, or ‐1
68 in case of error.
69
70 [1mint Cpool_assign(int [4m[22mpoolid[24m[1m, void
71*(*[4m[22mstartroutine[24m[1m)(void *), void
72*[4m[22marg[24m[1m,[0m
73 [1mint [4m[22mtimeout[24m[1m);[0m
74
75 This method is assigning a routine to [4mpoolid[24m as re‐
76turned by [1mCpool_cre‐[0m
77 [1mate[22m, whose address is [4mstartroutine[24m , that
78have the same prototype as
79 every typical routine in multithread programming. This
80means that it
81 returns a pointer, and it gets as entry a pointer identi‐
82fied by the [4marg[0m
83 parameter. The last argument is a possible [4mtimeout[24m
84, in seconds, which
85 will apply if it is greater than zero. If it is lower
86than zero, the
87 assignment will wait forever until a thread is avail‐
88able. If it is
89 equal to zero, the method will return immediately if
90no thread is
91 available.
92
93 Return value is 0 if success, or ‐1 in case of error.
94
95 [1mint Cpool_next_index(int [4m[22mpoolid[24m[1m);[0m
96
97 [1mint Cpool_next_index_timeout(int [4m[22mpoolid[24m[1m,
98int [4m[22mtimeout[24m[1m);[0m
99
100 Those methods returns that next available thread number
101that will be
102 assigned if you ever call [1mCpool_assign [22mimmediately
103after. If you spec‐
104 ify a timeout lower or equal than zero, then this is a
105blocking method
106 until one thread is available at least. Those methods,
107so, returns a
108 number greater or equal than zero, and ‐1 if there is an
109error.
110
111
112[1mNOTE[0m
113 [1mArguments passing in a non‐thread environment[0m
114
115 Since a forked process can only address its names‐
116pace data seg‐
117 ment, the address of the arguments, if any, valid
118in its parent,
119 will not be directly accessible for the child we
120are talking
121 about.
122
123 This means that Cpool, in a non‐thread envi‐
124ronment, have to
125 trace‐back all the memory allocation visible for
126the parent.
127 Then, Cpool is not passing the address of the argu‐
128ments, but its
129 content to the child through a child‐parent commu‐
130nication, moni‐
131 tored with a simple protocol.
132
133 There are four cases:
134 1.The address is NULL: nothing will be
135transmitted to
136 the child
137 2.The address is exactly a pointer re‐
138turned by mal‐
139 loc() or realloc(): the full malloced area
140will be tran‐
141 mitted.
142 3.The address is somewhere in a
143memory allocate
144 block: the remaining memory block, e.g.
145starting from the
146 address up to its end, will be transmitted.
147 4.the address do not point to any mem‐
148ory allocated
149 area: Cpool will assume it is a pointer‐
150like argument,
151 probably to some static variables, visible
152for all pro‐
153 cesses, and will transmit the content
154of the memory
155 pointed by the address, assuming it is coded
156on 64‐bits.
157 In any case, the user is passing a pointer, and the
158routine will
159 see a pointer, pointing to a (hopefully, see
160the point 4.,
161 listed upper) same‐content area.
162
163 [1mArguments design to work on both thread and non‐
164thread environ‐[0m
165 [1mments[0m
166
167 The thread and non‐thread arguments can have con‐
168ceptually a dif‐
169 ferent design when dealing with arguments;
170
171 In a thread environment, the routined passed to
172Cpool_assign, is
173 sharing memory, so is allowed to free() the ar‐
174gument, because
175 memory is then shared. On the contrary, in a non‐
176thread envi‐
177 ronment, this may be a segmentation fault.
178
179 This means that it is recommended to use static
180variables, con‐
181 taining simple value, like an integer (for exam‐
182ple: a socket
183 file descriptor), and not allocated memory. If,
184neverthless, you
185 persist to use free() in your routine, you can use
186the following
187 trick:
188
189 [1m/* ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ */[0m
190 [1m/* In the Caller Routine */[0m
191 [1m/* ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ */[0m
192
193 [1marg = malloc(...);[0m
194
195 [1mif (! Cpool_assign(...)) {[0m
196 [1mif (Cthread_environment() !=
197CTHREAD_TRUE_THREAD) {[0m
198 [1m/* Non‐Thread environment */[0m
199 [1mfree(arg);[0m
200 [1m} else {[0m
201 [1m/* Thread environment */[0m
202 [1m/* ... do nothing */[0m
203 [1m}[0m
204 [1m} else {[0m
205 [1m/* In cany case it is OK */[0m
206 [1mfree(arg);[0m
207 [1m}[0m
208
209 [1m/* ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ */[0m
210 [1m/* In the Execution Routine */[0m
211 [1m/* ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ */[0m
212
213 [1mvoid *routine(void *arg) {[0m
214 [1m./..[0m
215 [1mif (Cthread_environment() ==
216CTHREAD_TRUE_THREAD) {[0m
217 [1m/* Thread environment */[0m
218 [1mfree(arg);[0m
219 [1m} else {[0m
220 [1m/* Non‐Thread environment */[0m
221 [1m/* ... do nothing */[0m
222 [1m}[0m
223 [1m./..[0m
224 [1m}[0m
225
226[1mEXAMPLE[0m
227 #include <Cpool_api.h>
228 #include <stdio.h>
229 #include <errno.h>
230
231 #define NPOOL 2
232 #define PROCS_PER_POOL 2
233 #define TIMEOUT 2
234 void *testit(void *);
235
236 int main() {
237 int pid;
238 int i, j;
239 int ipool[NPOOL];
240 int npool[NPOOL];
241 int *arg;
242
243 pid = getpid();
244
245 printf("... Defining %d pools with %d elements each0,
246 NPOOL,PROCS_PER_POOL);
247
248 for (i=0; i < NPOOL; i++) {
249 if ((ipool[i] = Cpool_cre‐
250ate(PROCS_PER_POOL,&(npool[i]))) < 0) {
251 printf("### Error No %d creating pool (%s)0,
252 errno,strerror(errno));
253 } else {
254 printf("... Pool No %d created with %d processes0,
255 ipool[i],npool[i]);
256 }
257 }
258
259 for (i=0; i < NPOOL; i++) {
260 /* Loop on the number of processes + 1 ... */
261 for (j=0; j <= npool[i]; j++) {
262 if ((arg = malloc(sizeof(int))) == NULL) {
263 printf("### Malloc error, errno = %d (%s)0,
264 errno,strerror(errno));
265 continue;
266 }
267 *arg = i*10+j;
268 printf("... Assign to pool %d (timeout=%d) the %d‐th
269routine 0x%x(%d)0,
270 ipool[i],TIMEOUT,j+1,(unsigned int)
271testit,*arg);
272 if (Cpool_assign(ipool[i], testit, arg, TIMEOUT)) {
273 printf("### Can’t assign to pool No %d (errno=%d
274[%s]) the %d‐th routine0,
275 ipool[i],errno,strerror(errno),j);
276 free(arg);
277 } else {
278 printf("... Okay for assign to pool No %d of the
279%d‐th routine0,
280 ipool[i],j);
281 If (Cthread_environment() != CTHREAD_TRUE_THREAD)
282{
283 /* Non‐thread environment: the child is in prin‐
284ciple not allowed */
285 /* to do free himself
286*/
287 free(arg);
288 }
289 }
290 }
291 }
292
293 /* We wait enough time for our threads to terminate...
294*/
295 sleep(TIMEOUT*NPOOL*PROCS_PER_POOL);
296
297 exit(EXIT_SUCCESS);
298 }
299
300 void *testit(void *arg) {
301 int caller_pid, my_pid;
302
303 my_pid = getpid();
304
305 caller_pid = (int) * (int *) arg;
306
307 if (Cthread_environment() == CTHREAD_TRUE_THREAD) {
308 /* Thread environment : we free the memory */
309 free(arg);
310 }
311
312 printf("... I am PID=%d called by pool %d, try No %d0,
313 my_pid,caller_pid/10,caller_pid ‐ 10*(call‐
314er_pid/10));
315
316 /*
317 * Wait up to the timeout + 1
318 */
319 sleep(TIMEOUT*2);
320
321 return(NULL);
322 }
323
324
325
326
327
328[1mSEE ALSO[0m
329 [1mCthread[0m
330
331[1mAUTHOR[0m
332 [1mLCG Grid Deployment [22mTeam
333
334
335
336LCG $Date$
337CPOOL(3)
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