Cpool man page

CPOOL(3) Common Library Functions CPOOL(3)

[1mCpool [22m- [1mLCG Pool [22minferface

[1m#include <Cpool_api.h>[0m

[1mint Cpool_create(int [4m[22mnbwanted[24m[1m, int * [4m[22mnbget[24m[1m);[0m

[1mint Cpool_assign(int [4m[22mpoolid[24m[1m, void *(*[4m[22mstartroutine[24m[1m)(void *), void *[4m[22marg[24m[1m,[0m
[1mint [4m[22mtimeout[24m[1m);[0m

[1mint Cpool_next_index(int [4m[22mpoolid[24m[1m);[0m

[1mint Cpool_next_index_timeout(int [4m[22mpoolid[24m[1m, int [4m[22mtimeout[24m[1m);[0m

See [1mCthread [22mcorresponding section.

[1m(Please read the NOTE section)[0m

[1mCpool [22mis a layer built upon [1mCthread[22m, the [1mLCG Thread [22minterface. It
allows the user to create dedicated pools, and then to assign to one of
them a given routine to execute.

The created processes or threads will remain alive, unless the routines
assigned to are crashing, or explicitly calling an exit statement, like
exit() or pthread_exit().

Typical use might be writing a server, with a bunch of pre-created pro-
cesses or pools (depending on the environment with which [1mCthread [22mhas
been compiled), and assign to a given pool a routine with the socket
file descriptor as argument address.

In principle [1mCpool [22mshould be compiled with the same relevant flags with
which [1mCthread [22mhas been.

[1mint Cpool_create(int [4m[22mnbwanted[24m[1m, int * [4m[22mnbget[24m[1m);[0m

This method is creating a pool of [4mnbwanted[24m processes or threads. If the
second argument, [4mnbget[24m , is not NULL, its location will contain the
number of effectively created threads or processes.

Return value is the pool ID, a number greater or equal to zero, or -1
in case of error.

[1mint Cpool_assign(int [4m[22mpoolid[24m[1m, void *(*[4m[22mstartroutine[24m[1m)(void *), void *[4m[22marg[24m[1m,[0m
[1mint [4m[22mtimeout[24m[1m);[0m

This method is assigning a routine to [4mpoolid[24m as returned by [1mCpool_cre-[0m
[1mate[22m, whose address is [4mstartroutine[24m , that have the same prototype as
every typical routine in multithread programming. This means that it
returns a pointer, and it gets as entry a pointer identified by the [4marg[0m
parameter. The last argument is a possible [4mtimeout[24m , in seconds, which
will apply if it is greater than zero. If it is lower than zero, the
assignment will wait forever until a thread is available. If it is
equal to zero, the method will return immediately if no thread is

Return value is 0 if success, or -1 in case of error.

[1mint Cpool_next_index(int [4m[22mpoolid[24m[1m);[0m

[1mint Cpool_next_index_timeout(int [4m[22mpoolid[24m[1m, int [4m[22mtimeout[24m[1m);[0m

Those methods returns that next available thread number that will be
assigned if you ever call [1mCpool_assign [22mimmediately after. If you spec-
ify a timeout lower or equal than zero, then this is a blocking method
until one thread is available at least. Those methods, so, returns a
number greater or equal than zero, and -1 if there is an error.

[1mArguments passing in a non-thread environment[0m

Since a forked process can only address its namespace data seg-
ment, the address of the arguments, if any, valid in its parent,
will not be directly accessible for the child we are talking

This means that Cpool, in a non-thread environment, have to
trace-back all the memory allocation visible for the parent.
Then, Cpool is not passing the address of the arguments, but its
content to the child through a child-parent communication, moni-
tored with a simple protocol.

There are four cases:
1.The address is NULL: nothing will be transmitted to
the child
2.The address is exactly a pointer returned by mal-
loc() or realloc(): the full malloced area will be tran-
3.The address is somewhere in a memory allocate
block: the remaining memory block, e.g. starting from the
address up to its end, will be transmitted.
4.the address do not point to any memory allocated
area: Cpool will assume it is a pointer-like argument,
probably to some static variables, visible for all pro-
cesses, and will transmit the content of the memory
pointed by the address, assuming it is coded on 64-bits.
In any case, the user is passing a pointer, and the routine will
see a pointer, pointing to a (hopefully, see the point 4.,
listed upper) same-content area.

[1mArguments design to work on both thread and non-thread environ-[0m

The thread and non-thread arguments can have conceptually a dif-
ferent design when dealing with arguments;

In a thread environment, the routined passed to Cpool_assign, is
sharing memory, so is allowed to free() the argument, because
memory is then shared. On the contrary, in a non-thread envi-
ronment, this may be a segmentation fault.

This means that it is recommended to use static variables, con-
taining simple value, like an integer (for example: a socket
file descriptor), and not allocated memory. If, neverthless, you
persist to use free() in your routine, you can use the following

[1m/* ------------------------ */[0m
[1m/* In the Caller Routine */[0m
[1m/* ------------------------ */[0m

[1marg = malloc(...);[0m

[1mif (! Cpool_assign(...)) {[0m
[1mif (Cthread_environment() != CTHREAD_TRUE_THREAD) {[0m
[1m/* Non-Thread environment */[0m
[1m} else {[0m
[1m/* Thread environment */[0m
[1m/* ... do nothing */[0m
[1m} else {[0m
[1m/* In cany case it is OK */[0m

[1m/* ------------------------ */[0m
[1m/* In the Execution Routine */[0m
[1m/* ------------------------ */[0m

[1mvoid *routine(void *arg) {[0m
[1mif (Cthread_environment() == CTHREAD_TRUE_THREAD) {[0m
[1m/* Thread environment */[0m
[1m} else {[0m
[1m/* Non-Thread environment */[0m
[1m/* ... do nothing */[0m

#include <Cpool_api.h>
#include <stdio.h>
#include <errno.h>

#define NPOOL 2
#define PROCS_PER_POOL 2
#define TIMEOUT 2
void *testit(void *);

int main() {
int pid;
int i, j;
int ipool[NPOOL];
int npool[NPOOL];
int *arg;

pid = getpid();

printf("... Defining %d pools with %d elements each0,

for (i=0; i < NPOOL; i++) {
if ((ipool[i] = Cpool_create(PROCS_PER_POOL,&(npool[i]))) < 0) {
printf("### Error No %d creating pool (%s)0,
} else {
printf("... Pool No %d created with %d processes0,

for (i=0; i < NPOOL; i++) {
/* Loop on the number of processes + 1 ... */
for (j=0; j <= npool[i]; j++) {
if ((arg = malloc(sizeof(int))) == NULL) {
printf("### Malloc error, errno = %d (%s)0,
*arg = i*10+j;
printf("... Assign to pool %d (timeout=%d) the %d-th routine 0x%x(%d)0,
ipool[i],TIMEOUT,j+1,(unsigned int) testit,*arg);
if (Cpool_assign(ipool[i], testit, arg, TIMEOUT)) {
printf("### Can't assign to pool No %d (errno=%d [%s]) the %d-th routine0,
} else {
printf("... Okay for assign to pool No %d of the %d-th routine0,
If (Cthread_environment() != CTHREAD_TRUE_THREAD) {
/* Non-thread environment: the child is in principle not allowed */
/* to do free himself */

/* We wait enough time for our threads to terminate... */


void *testit(void *arg) {
int caller_pid, my_pid;

my_pid = getpid();

caller_pid = (int) * (int *) arg;

if (Cthread_environment() == CTHREAD_TRUE_THREAD) {
/* Thread environment : we free the memory */

printf("... I am PID=%d called by pool %d, try No %d0,
my_pid,caller_pid/10,caller_pid - 10*(caller_pid/10));

* Wait up to the timeout + 1


[1mSEE ALSO[0m

[1mLCG Grid Deployment [22mTeam

LCG $Date: 2010-04-05 09:51:26 +0200 (Mon, 05 Apr 2010) $ CPOOL(3)