Cpool man page

CPOOL(3)                   Common Library Functions                   CPOOL(3)

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

[1mSYNOPSIS[0m
      [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

[1mERRORS[0m
      See [1mCthread [22mcorresponding section.

[1mDESCRIPTION[0m
      [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
      available.

      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.

[1mNOTE[0m
             [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
             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, 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-
                    mitted.
                        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
             [1mments[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
             trick:

             [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
                 [1mfree(arg);[0m
               [1m} else {[0m
                 [1m/* Thread environment     */[0m
                 [1m/* ... do nothing         */[0m
               [1m}[0m
             [1m} else {[0m
                 [1m/* In cany case it is OK  */[0m
                 [1mfree(arg);[0m
             [1m}[0m

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

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

[1mEXAMPLE[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,
               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)0,
                   errno,strerror(errno));
          } else {
            printf("... Pool No %d created with %d processes0,
                   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)0,
                     errno,strerror(errno));
              continue;
            }
            *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,
                     ipool[i],errno,strerror(errno),j);
              free(arg);
            } else {
              printf("... Okay for assign to pool No %d of the %d-th routine0,
                     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 %d0,
               my_pid,caller_pid/10,caller_pid - 10*(caller_pid/10));

        /*
         * Wait up to the timeout + 1
         */
        sleep(TIMEOUT*2);

        return(NULL);
      }

[1mSEE ALSO[0m
      [1mCthread[0m

[1mAUTHOR[0m
      [1mLCG Grid Deployment [22mTeam

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