---
name: "Cglobals"
section: "3"
platform: "linux"
package: "liblcgdm-dev"
version: "1.10.0-2+b3"
release: "Debian 10 (Buster)"
platforms: ["linux"]
url: "https://new.carta.tech/Cglobals"
---

# Cglobals(3)

LCG thread-specific global variables interface

## NAME

**Cglobals** - LCG thread-specific **global** variable**s** 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)](/Cthread/3.md), [serrno(3)](/serrno/3.md), [Cgetopt(3)](/Cgetopt/3.md)**

## AUTHOR

**LCG Grid Deployment Team**
