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
Impressum