1CPOOL(3) Common Library Functions CPOOL(3)
2
3
4
6 Cpool - LCG Pool inferface
7
9 #include <Cpool_api.h>
10
11 int Cpool_create(int nbwanted, int * nbget);
12
13 int Cpool_assign(int poolid, void *(*startroutine)(void *), void *arg,
14 int timeout);
15
16 int Cpool_next_index(int poolid);
17
18 int Cpool_next_index_timeout(int poolid, int timeout);
19
20
22 See Cthread corresponding section.
23
24
26 (Please read the NOTE section)
27
28 Cpool is a layer built upon Cthread, the LCG Thread interface. It
29 allows the user to create dedicated pools, and then to assign to one of
30 them a given routine to execute.
31
32 The created processes or threads will remain alive, unless the routines
33 assigned to are crashing, or explicitly calling an exit statement, like
34 exit() or pthread_exit().
35
36 Typical use might be writing a server, with a bunch of pre-created pro‐
37 cesses or pools (depending on the environment with which Cthread has
38 been compiled), and assign to a given pool a routine with the socket
39 file descriptor as argument address.
40
41 In principle Cpool should be compiled with the same relevant flags with
42 which Cthread has been.
43
44 int Cpool_create(int nbwanted, int * nbget);
45
46 This method is creating a pool of nbwanted processes or threads. If the
47 second argument, nbget , is not NULL, its location will contain the
48 number of effectively created threads or processes.
49
50 Return value is the pool ID, a number greater or equal to zero, or -1
51 in case of error.
52
53 int Cpool_assign(int poolid, void *(*startroutine)(void *), void *arg,
54 int timeout);
55
56 This method is assigning a routine to poolid as returned by Cpool_cre‐
57 ate, whose address is startroutine , that have the same prototype as
58 every typical routine in multithread programming. This means that it
59 returns a pointer, and it gets as entry a pointer identified by the arg
60 parameter. The last argument is a possible timeout , in seconds, which
61 will apply if it is greater than zero. If it is lower than zero, the
62 assignment will wait forever until a thread is available. If it is
63 equal to zero, the method will return immediately if no thread is
64 available.
65
66 Return value is 0 if success, or -1 in case of error.
67
68 int Cpool_next_index(int poolid);
69
70 int Cpool_next_index_timeout(int poolid, int timeout);
71
72 Those methods returns that next available thread number that will be
73 assigned if you ever call Cpool_assign immediately after. If you spec‐
74 ify a timeout lower or equal than zero, then this is a blocking method
75 until one thread is available at least. Those methods, so, returns a
76 number greater or equal than zero, and -1 if there is an error.
77
78
80 Arguments passing in a non-thread environment
81
82 Since a forked process can only address its namespace data seg‐
83 ment, the address of the arguments, if any, valid in its parent,
84 will not be directly accessible for the child we are talking
85 about.
86
87 This means that Cpool, in a non-thread environment, have to
88 trace-back all the memory allocation visible for the parent.
89 Then, Cpool is not passing the address of the arguments, but its
90 content to the child through a child-parent communication, moni‐
91 tored with a simple protocol.
92
93 There are four cases:
94 1.The address is NULL: nothing will be transmitted to
95 the child
96 2.The address is exactly a pointer returned by mal‐
97 loc() or realloc(): the full malloced area will be tran‐
98 mitted.
99 3.The address is somewhere in a memory allocate
100 block: the remaining memory block, e.g. starting from the
101 address up to its end, will be transmitted.
102 4.the address do not point to any memory allocated
103 area: Cpool will assume it is a pointer-like argument,
104 probably to some static variables, visible for all pro‐
105 cesses, and will transmit the content of the memory
106 pointed by the address, assuming it is coded on 64-bits.
107 In any case, the user is passing a pointer, and the routine will
108 see a pointer, pointing to a (hopefully, see the point 4.,
109 listed upper) same-content area.
110
111 Arguments design to work on both thread and non-thread environ‐
112 ments
113
114 The thread and non-thread arguments can have conceptually a dif‐
115 ferent design when dealing with arguments;
116
117 In a thread environment, the routined passed to Cpool_assign, is
118 sharing memory, so is allowed to free() the argument, because
119 memory is then shared. On the contrary, in a non-thread envi‐
120 ronment, this may be a segmentation fault.
121
122 This means that it is recommended to use static variables, con‐
123 taining simple value, like an integer (for example: a socket
124 file descriptor), and not allocated memory. If, neverthless, you
125 persist to use free() in your routine, you can use the following
126 trick:
127
128 /* ------------------------ */
129 /* In the Caller Routine */
130 /* ------------------------ */
131
132 arg = malloc(...);
133
134 if (! Cpool_assign(...)) {
135 if (Cthread_environment() != CTHREAD_TRUE_THREAD) {
136 /* Non-Thread environment */
137 free(arg);
138 } else {
139 /* Thread environment */
140 /* ... do nothing */
141 }
142 } else {
143 /* In cany case it is OK */
144 free(arg);
145 }
146
147 /* ------------------------ */
148 /* In the Execution Routine */
149 /* ------------------------ */
150
151 void *routine(void *arg) {
152 ./..
153 if (Cthread_environment() == CTHREAD_TRUE_THREAD) {
154 /* Thread environment */
155 free(arg);
156 } else {
157 /* Non-Thread environment */
158 /* ... do nothing */
159 }
160 ./..
161 }
162
164 #include <Cpool_api.h>
165 #include <stdio.h>
166 #include <errno.h>
167
168 #define NPOOL 2
169 #define PROCS_PER_POOL 2
170 #define TIMEOUT 2
171 void *testit(void *);
172
173 int main() {
174 int pid;
175 int i, j;
176 int ipool[NPOOL];
177 int npool[NPOOL];
178 int *arg;
179
180 pid = getpid();
181
182 printf("... Defining %d pools with %d elements each\n",
183 NPOOL,PROCS_PER_POOL);
184
185 for (i=0; i < NPOOL; i++) {
186 if ((ipool[i] = Cpool_create(PROCS_PER_POOL,&(npool[i]))) < 0) {
187 printf("### Error No %d creating pool (%s)\n",
188 errno,strerror(errno));
189 } else {
190 printf("... Pool No %d created with %d processes\n",
191 ipool[i],npool[i]);
192 }
193 }
194
195 for (i=0; i < NPOOL; i++) {
196 /* Loop on the number of processes + 1 ... */
197 for (j=0; j <= npool[i]; j++) {
198 if ((arg = malloc(sizeof(int))) == NULL) {
199 printf("### Malloc error, errno = %d (%s)\n",
200 errno,strerror(errno));
201 continue;
202 }
203 *arg = i*10+j;
204 printf("... Assign to pool %d (timeout=%d) the %d-th routine 0x%x(%d)\n",
205 ipool[i],TIMEOUT,j+1,(unsigned int) testit,*arg);
206 if (Cpool_assign(ipool[i], testit, arg, TIMEOUT)) {
207 printf("### Can't assign to pool No %d (errno=%d [%s]) the %d-th routine\n",
208 ipool[i],errno,strerror(errno),j);
209 free(arg);
210 } else {
211 printf("... Okay for assign to pool No %d of the %d-th routine\n",
212 ipool[i],j);
213 If (Cthread_environment() != CTHREAD_TRUE_THREAD) {
214 /* Non-thread environment: the child is in principle not allowed */
215 /* to do free himself */
216 free(arg);
217 }
218 }
219 }
220 }
221
222 /* We wait enough time for our threads to terminate... */
223 sleep(TIMEOUT*NPOOL*PROCS_PER_POOL);
224
225 exit(EXIT_SUCCESS);
226 }
227
228 void *testit(void *arg) {
229 int caller_pid, my_pid;
230
231 my_pid = getpid();
232
233 caller_pid = (int) * (int *) arg;
234
235 if (Cthread_environment() == CTHREAD_TRUE_THREAD) {
236 /* Thread environment : we free the memory */
237 free(arg);
238 }
239
240 printf("... I am PID=%d called by pool %d, try No %d\n",
241 my_pid,caller_pid/10,caller_pid - 10*(caller_pid/10));
242
243 /*
244 * Wait up to the timeout + 1
245 */
246 sleep(TIMEOUT*2);
247
248 return(NULL);
249 }
250
251
252
253
254
256 Cthread
257
259 LCG Grid Deployment Team
260
261
262
263LCG $Date: 2010-04-05 09:51:26 +0200 (Mon, 05 Apr 2010) $ CPOOL(3)