Man Linux: Main Page and Category List

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