Cglobals man page

CGLOBALS(3)                Common Library Functions                CGLOBALS(3)

[1mNAME[0m
      [1mCglobals [22m- LCG thread-specific [1mglobal [22mvariable[1ms [22minterface

[1mSYNOPSIS[0m
      [1m#include <Cglobals.h>[0m

      [1mvoid Cglobals_init([0m
             [1mint (*[4m[22mgetspec[24m[1m) (int *[4m[22mkey[24m[1m, void **[4m[22maddr[24m[1m),[0m
             [1mint (*[4m[22msetspec[24m[1m) (int *[4m[22mkey[24m[1m, void *[4m[22maddr[24m[1m),[0m
             [1mint (*[4m[22mgetTid[24m[1m) (void)[0m
      [1m);[0m

      [1mint Cglobals_get(int *[4m[22mkey[24m[1m, void **[4m[22maddr[24m[1m, size_t [4m[22msize[24m[1m);[0m

      [1mvoid Cglobals_getTid(int *[4m[22mTid[24m[1m);[0m

      [1mint C__serrno();[0m

      [1mint C__rfio_errno();[0m

      [1mint C__Copterr();[0m

      [1mint C__Coptind();[0m

      [1mint C__Coptopt();[0m

      [1mint C__Coptreset();[0m

      [1mchar *C__Coptarg();[0m

      [1mint C__h_errno();[0m

[1mDESCRIPTION[0m
      [1mCglobals  [22mis  the  interface  where are defined all necessary functions
      that always return a thread-specific value of  global  variables.  Each
      package  of  [1mLCG [22mthat needs to externalize thread-specific global vari-
      ables contains in its header, if compiled with threads turned on  (e.g.
      the default), a set of:
             an [1mextern [22mdefinition to a function contained in Cglobals
             a [1m#define [22mmacro that replaces all occurences of any global vari-
             able that needs to be thread-specific to  this  Cglobal's  func-
             tion.
      In  order  to  satisfy packages not compiled with threads turned on, or
      that do not initialize [1mLCG [22mThread Interface's [1mCthread[22m, any such  global
      variable is also explicitly defined in [1mCglobals[22m.

      For  example,  taking the global error variable [1mserrno[22m, [1mCglobals [22msource
      code contains:
             an explicit definition of this variable [1mserrno[0m
             an explicit definition, with source code, of a  function  [1mC_ser-[0m
             [1mrno() [22mthat does only the following:
                    if  [1mCglobals_init  [22mwas  not (successfully) called, return
                    the address of the global variable [1mserrno[0m
                    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 [1mserrno[0m

      The  following  description  of  [1mCglobals_init  [22mfunction  is explaining
      internals of [1mCglobals [22mand [1mCthread[22m. In theory no LCG application need to
      call  [1mCglobals_init[22m, you can skip if you want the following paragraphs,
      and concentrate only on the other functions descriptions.

      [1mCglobals_init [22mis bundled  to  work  with  the  [1mLCG  [22mThread  Interface's
      [1mCthread[22m. That is, any implicit or explicit call to [1mCthread [22malways makes
      sure that [1mCglobals_init [22mis called, with three arguments that are:
             a [4mgetspec[24m function address that, given  a  static  [4mkey[24m  address,
             returns  the  address of a Thread-Specific memory into [4maddr[24m con-
             tent. This uses an internal structure inside [1mCthread[22m,  allocated
             on  the  heap,  that  is  associated bijectively to [4mkey[24m address.
             [1mCthread [22malways explicitly allocates such internal  structure  to
             any  [4mkey[24m  address  if it is unknown at the moment of the call to
             [4mgetspec.[0m
             In such a case it will return a NULL value into [4maddr[24m  ,  and  it
             will be the responsability of [1mCglobals [22mto allocate memory on the
             heap and to say to [1mCthread [22mthat this newly allocated  memory  is
             the one to associate with [4mkey[24m address, using [4msetspec.[0m
             If  the  internal structure in [1mCthread [22massociated bijectively to
             [4mkey[24m yet exists, [4mgetspec[24m only returns what  it  knows  about  the
             thread-specific  memory  associated  with  it, which is a [1mvoid *[0m
             member inside the same internal structure mentionned above.

             a [4msetspec[24m function address that, given the [4mkey[24m address  and  the
             [4maddr[24m  value,  previously  instanciated  with a [4mgetspec[24m call, and
             possibly allocated on the heap by [1mCglobals  [22mif  necessary,  will
             internally  explicitly call the Operating System Thread-Specific
             functions that will  put  the  value  of  [4maddress[24m  as  something
             thread-specific, bijectively associated to another member of the
             internal structure of [1mCthread[22m, itself bijective to [4mkey.[0m

             a [4mgetTid[24m function address that returns an unique integer identi-
             fier associated with any thread.

      [1mCglobals_get  [22mreturns  in [4maddr[24m 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 [4mkey[24m , that is automati-
      cally created and filled with zeros if necessary, up to [4msize[24m bytes.
      If the [4maddr[24m content, at return of [1mCglobals_get[22m, is not  NULL,  you  can
      safely  fill  this  memory with any value, provided you does not exceed
      the [4msize[24m bytes length specified in your previous call to  [1mCglobals_get[22m.
      Because  of applications that are [1mnot [22mmulti-threaded, the initial value
      of [4mkey[24m 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 [1mnot [22mthe first call for
      this [4mkey[24m , 1 on success and [1mit is [22mthe first call for  this  [4mkey.[24m   This
      allows  to  distinguish  when Cglobals_get() initialize the memory with
      zeros (return code 1) and not (return code 0).

      [1mCglobals_getTid [22muses the third function address, [4mgetTid[24m , given  as  an
      argument  to  [1mCglobals_init[22m,  and  will return in [4mTid[24m content the value
      returned by [4mgetTid.[0m

      [1mC__serrno[22m, [1mC__rfio_errno[22m, [1mC__Copterr[22m, [1mC__Coptind[22m,  [1mC__Coptopt[22m,  [1mC__Cop-[0m
      [1mtreset[22m,  [1mC__Coptarg  [22mand [1mC__h_errno [22mare 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.

[1mEXAMPLE[0m
      Any application can create its own instance of  thread-specific  global
      variable using [1mCglobals[22m. You need only to use [1mCglobals_get[22m. 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 [1mCglobals_get [22mprototype */
      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);
      }

[1mSEE ALSO[0m
      [1mCthread[22m(3), [1mserrno[22m(3), [1mCgetopt[22m(3)

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

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