Provided by: liblcgdm-dev_1.10.0-2_amd64 bug

NAME

       Cglobals - LCG thread-specific global variables interface

SYNOPSIS

       #include <Cglobals.h>

       void Cglobals_init(
              int (*getspec) (int *key, void **addr),
              int (*setspec) (int *key, void *addr),
              int (*getTid) (void)
       );

       int Cglobals_get(int *key, void **addr, size_t size);

       void Cglobals_getTid(int *Tid);

       int C__serrno();

       int C__rfio_errno();

       int C__Copterr();

       int C__Coptind();

       int C__Coptopt();

       int C__Coptreset();

       char *C__Coptarg();

       int C__h_errno();

DESCRIPTION

       Cglobals  is  the interface where are defined all necessary functions that always return a
       thread-specific value of global variables. Each package of LCG that needs  to  externalize
       thread-specific  global  variables contains in its header, if compiled with threads turned
       on (e.g. the default), a set of:
              an extern definition to a function contained in Cglobals
              a #define macro that replaces all occurences of any global variable that  needs  to
              be thread-specific to this Cglobal's function.
       In  order  to  satisfy  packages  not  compiled  with  threads  turned  on, or that do not
       initialize LCG Thread Interface's Cthread, any such global  variable  is  also  explicitly
       defined in Cglobals.

       For example, taking the global error variable serrno, Cglobals source code contains:
              an explicit definition of this variable serrno
              an  explicit  definition, with source code, of a function C_serrno() that does only
              the following:
                     if Cglobals_init was not (successfully) called, return the  address  of  the
                     global variable serrno
                     else  return  the  address of a thread-safe specific memory, instanciated at
                     the first call to this function, that  holds  the  content  of  the  current
                     instance of the thread-specific value of serrno

       The  following  description  of Cglobals_init function is explaining internals of Cglobals
       and Cthread. In theory no LCG application need to call Cglobals_init, you can skip if  you
       want the following paragraphs, and concentrate only on the other functions descriptions.

       Cglobals_init  is  bundled  to  work with the LCG Thread Interface's Cthread. That is, any
       implicit or explicit call to Cthread always makes sure that Cglobals_init is called,  with
       three arguments that are:
              a getspec function address that, given a static key address, returns the address of
              a Thread-Specific memory into addr content. This uses an internal structure  inside
              Cthread,  allocated  on  the  heap,  that is associated bijectively to key address.
              Cthread always explicitly allocates such internal structure to any key  address  if
              it is unknown at the moment of the call to getspec.
              In  such  a  case  it  will  return  a  NULL  value  into addr , and it will be the
              responsability of Cglobals to allocate memory on the heap and  to  say  to  Cthread
              that  this  newly  allocated memory is the one to associate with key address, using
              setspec.
              If the internal structure in Cthread associated  bijectively  to  key  yet  exists,
              getspec only returns what it knows about the thread-specific memory associated with
              it, which is a void * member inside the same internal structure mentionned above.

              a setspec function address  that,  given  the  key  address  and  the  addr  value,
              previously  instanciated with a getspec call, and possibly allocated on the heap by
              Cglobals if necessary, will internally explicitly call the Operating System Thread-
              Specific functions that will put the value of address as something thread-specific,
              bijectively associated to another member of  the  internal  structure  of  Cthread,
              itself bijective to key.

              a getTid function address that returns an unique integer identifier associated with
              any thread.

       Cglobals_get returns in addr content the address of a thread-specific memory, e.g. thread-
       safe,  that  is  bijectively  associated  with  the  address of a *static*, e.g. constant,
       address key , that is automatically created and filled with zeros if necessary, up to size
       bytes.
       If  the  addr  content,  at  return of Cglobals_get, is not NULL, you can safely fill this
       memory with any value, provided you does not exceed the size  bytes  length  specified  in
       your  previous  call to Cglobals_get. Because of applications that are not multi-threaded,
       the initial value of key has then an importance, that's why  it  is  necessary  to  always
       declare it with an initial value of -1.

       Return  code  is  -1  on  error,  0  on success and not the first call for this key , 1 on
       success and it is  the  first  call  for  this  key.   This  allows  to  distinguish  when
       Cglobals_get() initialize the memory with zeros (return code 1) and not (return code 0).

       Cglobals_getTid  uses  the  third  function  address,  getTid  ,  given  as an argument to
       Cglobals_init, and will return in Tid content the value returned by getTid.

       C__serrno, C__rfio_errno, C__Copterr, C__Coptind, C__Coptopt, C__Coptreset, C__Coptarg and
       C__h_errno  are  all the internal functions that return the address of the thread-specific
       memory hosting the value of the 'global' variables serrno, rfio_errno,  Copterr,  Coptind,
       Coptopt, Coptreset, Coptarg and h_errno, respectively.

EXAMPLE

       Any  application  can  create  its  own  instance of thread-specific global variable using
       Cglobals. You need only to use Cglobals_get. Here is how to proceed.

       /*
        * The following shows how to define and use a thread-specific
        * integer, my_var, inside your package
        */

       #include <stdlib.h>
       #include <stdio.h>
       #include <Cglobals.h>   /* Get Cglobals_get prototype */
       static int my_key = -1; /* Our static key, integer, init value -1 */
       #define my_var (*C__my_var())

       static int my_var_static; /* If Cglobals_get error in order not to crash */

       int *C__my_var()
       {
               int *var;
               /* Call Cglobals_get */
               Cglobals_get(&my_key,
                            (void **) &var,
                            sizeof(int)
                           );
               /* If error, var will be NULL */
               if (var == NULL)
               {
                       fprintf(stderr,"Cglobals_get error0);
                       return(&my_var_static);
               }
               return(var);
       }

       int main()
       {
               fprintf(stdout, "Current my_var value is: %d0, my_var);
               fprintf(stdout, "Set my_var value to: %d0, 12);
               my_var = 12;
               fprintf(stdout, "Current my_var value is: %d0, my_var);
               return(0);
       }

       The following example is the source of the test suite for Cglobals_get():

       #include <Cthread_api.h>
       #include <stdlib.h>
       #include <stdio.h>
       #include <Cglobals.h>   /* Get Cglobals_get prototype */
       #include <serrno.h>

       static int my_key = -1; /* Our static key, integer, init value -1 */
       #define my_var (*C__my_var())

       static int my_var_static; /* If Cglobals_get error in order not to crash */
       void *doit _PROTO((void *));

       int doit_v = 0;
       #define NTHREAD 100

       int *C__my_var()
       {
         int *var;
         /* Call Cglobals_get */
         switch (Cglobals_get(&my_key,
                              (void **) &var,
                              sizeof(int)
                              )) {
         case -1:
           fprintf(stderr,"[%d] Cglobals_get error0, Cthread_self());
           break;
         case 0:
           fprintf(stderr,"[%d] Cglobals_get OK0, Cthread_self());
           break;
         case 1:
           fprintf(stderr,"[%d] Cglobals_get OK and first call0, Cthread_self());
           break;
         default:
           fprintf(stderr,"[%d] Cglobals_get unknown return code0, Cthread_self());
           break;
         }
         /* If error, var will be NULL */
         if (var == NULL) {
           fprintf(stderr,"[%d] Cglobals_get error : RETURN static ADDRESS!!!!!!!!!!!!0, Cthread_self());
           return(&my_var_static);
         }
         return(var);
       }

       int main()
       {
         int i;

         fprintf(stdout, "[%d] ---> Before any Cthread call0, -1);
         fprintf(stdout, "[%d] Current my_var value is: %d0, -1, my_var);
         fprintf(stdout, "[%d] Set my_var value to: %d0, -1, 12);
         my_var = 12;
         fprintf(stdout, "[%d] Current my_var value is: %d0, -1, my_var);
         fprintf(stdout, "[%d] Testing consistency0, -1);
         if (my_var != 12) {
           fprintf(stdout, "[%d] Cglobals_get worked ok0, -1);
           exit(1);
         }
         sleep(1);
         for (i = 0; i < NTHREAD; i++) {
           Cthread_create(&doit, &doit_v);
           doit_v++;
         }
         fprintf(stdout, "[%d] ---> After all Cthread_create calls0, -1);
         fprintf(stdout, "[%d] Current my_var value is: %d0, -1, my_var);
         fprintf(stdout, "[%d] Set my_var value to: %d0, -1, NTHREAD * 10000 + 12);
         my_var = NTHREAD * 10000 + 12;
         fprintf(stdout, "[%d] Current my_var value is: %d0, -1, my_var);
         fprintf(stdout, "[%d] Testing consistency0, -1);
         if (my_var != (NTHREAD * 10000 + 12)) {
           fprintf(stdout, "[%d] Cglobals_get worked ok0, -1);
           exit(1);
         }
         sleep(1);
         exit(0);
       }

       void *doit(arg)
            void *arg;
       {
         int Tid;
         int doit = * (int *) arg;
         Cglobals_getTid(&Tid);
         my_var = (Tid + 1) * 100 + 12;
         fprintf(stdout, "[%d] my_var value is: %d (should be %d)0, Cthread_self(), my_var, (Tid + 1) * 100 + 12);
         fprintf(stdout, "[%d] second call -- my_var value is: %d (should be %d)0, Cthread_self(), my_var, (Tid + 1) * 100 + 12);
         fprintf(stdout, "[%d] Testing consistency0, Cthread_self());
         if (my_var != ((Tid + 1) * 100 + 12)) {
           fprintf(stdout, "[%d] !!!!!!!!! ERROR !!!!!!!!!0, Cthread_self());
           exit(1);
         } else {
           fprintf(stdout, "[%d] Cglobals_get worked ok0, Cthread_self());
         }
         return(0);
       }

SEE ALSO

       Cthread(3), serrno(3), Cgetopt(3)

AUTHOR

       LCG Grid Deployment Team