CGLOBALS(3) | Common Library Functions | CGLOBALS(3) |
Cglobals - LCG thread-specific global variables interface
#include <Cglobals.h>
void Cglobals_init(
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();
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:
For example, taking the global error variable serrno, Cglobals source code contains:
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 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.
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); }
LCG Grid Deployment Team
$Date: 2010-04-05 09:51:26 +0200 (Mon, 05 Apr 2010) $ | LCG |