| CPOOL(3) | Common Library Functions | CPOOL(3) |
NAME¶
Cpool - LCG Pool inferfaceSYNOPSIS¶
#include <Cpool_api.h> int Cpool_create(int nbwanted, int * nbget); int Cpool_assign(int poolid, void *(*startroutine)(void *), void *arg, int timeout); int Cpool_next_index(int poolid); int Cpool_next_index_timeout(int poolid, int timeout);ERRORS¶
See Cthread corresponding section.DESCRIPTION¶
(Please read the NOTE section)NOTE¶
Arguments passing in a non-thread
environment
Since a forked process can only address its namespace data segment, the address
of the arguments, if any, valid in its parent, will not be directly accessible
for the child we are talking about.
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, monitored 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 malloc() or realloc(): the full malloced area will be tranmitted.
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 processes, 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.
Arguments design to work on both thread and non-thread environments
The thread and non-thread arguments can have conceptually a different 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 environment, this may be a segmentation fault.
This means that it is recommended to use static variables, containing 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 trick:
1.The address is NULL: nothing will be transmitted to the child
2.The address is exactly a pointer returned by malloc() or realloc(): the full malloced area will be tranmitted.
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 processes, and will transmit the content of the memory pointed by the address, assuming it is coded on 64-bits.
/* ------------------------ */ /* In the Caller Routine */ /* ------------------------ */ arg = malloc(...); if (! Cpool_assign(...)) { if (Cthread_environment() != CTHREAD_TRUE_THREAD) { /* Non-Thread environment */ free(arg); } else { /* Thread environment */ /* ... do nothing */ } } else { /* In cany case it is OK */ free(arg); } /* ------------------------ */ /* In the Execution Routine */ /* ------------------------ */ void *routine(void *arg) { ./.. if (Cthread_environment() == CTHREAD_TRUE_THREAD) { /* Thread environment */ free(arg); } else { /* Non-Thread environment */ /* ... do nothing */ } ./.. }
EXAMPLE¶
#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 each\n", NPOOL,PROCS_PER_POOL); for (i=0; i < NPOOL; i++) { if ((ipool[i] = Cpool_create(PROCS_PER_POOL,&(npool[i]))) < 0) { printf("### Error No %d creating pool (%s)\n", errno,strerror(errno)); } else { printf("... Pool No %d created with %d processes\n", ipool[i],npool[i]); } } 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)\n", errno,strerror(errno)); continue; } *arg = i*10+j; printf("... Assign to pool %d (timeout=%d) the %d-th routine 0x%x(%d)\n", 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 routine\n", ipool[i],errno,strerror(errno),j); free(arg); } else { printf("... Okay for assign to pool No %d of the %d-th routine\n", ipool[i],j); If (Cthread_environment() != CTHREAD_TRUE_THREAD) { /* Non-thread environment: the child is in principle not allowed */ /* to do free himself */ free(arg); } } } } /* We wait enough time for our threads to terminate... */ sleep(TIMEOUT*NPOOL*PROCS_PER_POOL); exit(EXIT_SUCCESS); } 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 */ free(arg); } printf("... I am PID=%d called by pool %d, try No %d\n", my_pid,caller_pid/10,caller_pid - 10*(caller_pid/10)); /* * Wait up to the timeout + 1 */ sleep(TIMEOUT*2); return(NULL); }
SEE ALSO¶
CthreadAUTHOR¶
LCG Grid Deployment Team| $Date: 2010-04-05 09:51:26 +0200 (Mon, 05 Apr 2010) $ | LCG |