I'm trying to share a variable with c and tcl, the problem is when i try to read the variable in the c thread from tcl, it causes segmentation error, i'm not sure this is the right way to do it, but it seems to work for ints. The part that is causing the segmentation fault is this line is when i try to print "Var" but i want to read the variable to do the corresponding action when the variable changes.
Here is the C code that i'm using
void mode_service(ClientData clientData) {
while(1) {
char* Var = (char *) clientData;
printf("%s\n", Var);
usleep(100000); //100ms
}
}
static int mode_thread(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
Tcl_ThreadId id;
ClientData limitData;
limitData = cdata;
id = 0;
Tcl_CreateThread(&id, mode_service, limitData, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS);
printf("Tcl_CreateThread id = %d\n", (int) id);
// Wait thread process, before returning to TCL prog
int i, aa;
for (i=0 ; i<100000; i++) {aa = i;}
// Return thread ID to tcl prog to allow mutex use
Tcl_SetObjResult(interp, Tcl_NewIntObj((int)id));
printf("returning\n");
return TCL_OK;
}
int DLLEXPORT Modemanager_Init(Tcl_Interp *interp){
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
if (Tcl_PkgProvide(interp, "PCIe", "1.0") == TCL_ERROR) {
return TCL_ERROR;
}
// Create global Var
int *sharedPtr=NULL;
//sharedPtr = sharedPtr = (char *) Tcl_Alloc(sizeof(char));
Tcl_LinkVar(interp, "mode", (char *) &sharedPtr, TCL_LINK_STRING);
Tcl_CreateObjCommand(interp, "mode_thread", mode_thread, sharedPtr, NULL);
return TCL_OK;
}
In the tcl code, i'm changing the variable mode whenever the user presses a button for example:
set mode "Idle"
button .startSamp -text "Sample Start" -width 9 -height 3 -background $btnColor -relief flat -state normal -command {set mode "Sampling"}
set threadId [mode_thread]
puts "Created thread $threadId, waiting"
Your code is a complete mess! You need to decide what you are doing and then do just that. In particular, you are using Tcl_LinkVar so you need to decide what sort of variable you are linking to. If you get a mismatch between the storage, the C access pattern and the declared semantic type, you'll get crashes.
Because your code is in too complicated a mess for me to figure out exactly what you want to do, I'll illustrate with less closely related examples. You'll need to figure out from them how to change things in your code to get the result you need.
Linking Integer Variables
Let's do the simple case: a global int variable (declared outside any function).
int sharedVal;
You want your C code to read that variable and get the value. Easy! Just read it as it is in scope. You also want Tcl code to be able to write to that variable. Easy! In the package initialization function, put this:
Tcl_LinkVar(interp /* == the Tcl interpreter context */,
"sharedVal" /* == the Tcl name */,
(char *) &sharedVal /* == pointer to C variable */,
TCL_LINK_INT /* == what is it! An integer */);
Note that after that (until you Tcl_UnlinkVar) whenever Tcl code reads from the Tcl variable, the current value will be fetched from the C variable and converted.
If you want that variable to be on the heap, you then do:
int *sharedValPtr = malloc(sizeof(int));
C code accesses using *sharedValPtr, and you bind to Tcl with:
Tcl_LinkVar(interp /* == the Tcl interpreter context */,
"sharedVal" /* == the Tcl name */,
(char *) sharedValPtr /* == pointer to C variable */,
TCL_LINK_INT /* == what is it! An integer */);
Linking String Variables
There's a bunch of other semantic types as well as TCL_LINK_INT (see the documentation for a list) but they all follow that pattern except for TCL_LINK_STRING. With that, you do:
char *sharedStr = NULL;
Tcl_LinkVar(interp, "sharedStr", (char *) &sharedStr, TCL_LINK_STRING);
You also need to be aware that the string will always be allocated with Tcl_Alloc (which is substantially faster than most system memory allocators for typical Tcl memory usage patterns) and not with any other memory allocator, and so will also always be deallocated with Tcl_Free. Practically, that means if you set the string from the C side, you must use Tcl_Alloc to allocate the memory.
Posting Update Notifications
The final piece to note is when you set the variable from the C side but want Tcl to notice that the change has set (e.g., because a trace has been set or because you've surfaced the value in a Tk GUI), you should do Tcl_UpdateLinkedVar to let Tcl know that a change has happened that it should pay attention to. If you never use traces (or Tk GUIs, or the vwait command) to watch the variable for updates, you can ignore this API call.
Donal's answer is correct, but I try to show you what you did with your ClientData.
To clarify: All (or almost all, Idk) Tcl functions that take a function pointer also take a parameter of type ClientData that is passed to your function when Tcl calls it.
Let's take a look at this line:
Tcl_CreateObjCommand(interp, "mode_thread", mode_thread, NULL, NULL);
// ------------------------------------------------------^^^^
You always pass NULL as ClientData to the mode_thread function.
In the mode_thread function you use the passed ClientData (NULL) to pass it as ClientData to the new Thread:
limitData = cdata;
// ...
Tcl_CreateThread(&id, mode_service, limitData, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS);
In the mode_service function you use the ClientData (which is still NULL) as pointer to a char array:
char* Var = (char *) clientData;
Which is a pointer to the address 0x00.
And then you tell printf to dereference this NULL pointer:
printf("%s\n", Var);
Which obviously crashes your program.
Related
I want to parse output from a commandline tool using the fsm programming model. What is the simplest implementation of a fsm that is possible for this task?
Basically, the core idea of a finite state machine is that the machine is in a "state" and, for every state, the behaviour of the machine is different from other states.
A simple way to do this is to have an integer variable (or an enum) which stores the status, and a switch() statement which implements, for every case, the required logic.
Suppose you have a file of the followin kind:
something
begin
something
something2
end
something
and you duty is to print the part between begin/end. You read the file line by line, and switch state basing on the content of the line:
// pseudo-C code
enum state {nothing, inblock};
enum state status;
string line;
status = nothing;
while (!eof(file)) {
readline(line);
switch(status) {
case nothing:
if (line == "begin") status=inblock;
break;
case inblock:
if (line == "end")
status=nothing;
else print(line);
break;
}
}
In this example, only the core idea is shown: a "status" of the machine and a mean to change status (the "line" read from file). In real life examples probably there are more variables to keep more informations for every state and, perhaps, the "status" of the machine can be stored in a function pointer, to avoid the burden and rigidity of the switch() statement but, even so, the programming paradigm is clean and powerful.
The fsm model works in C by assigning function pointers to certain functions that have to process certain data. One good use for fsms is for parsing commandline arguments, for parsing captured output.... The function pointer is assigned to a preset starting function. The start function assigns the function pointer, which must be passed along, to the appropriate next function. And that decides the next function and so on.
Here is a very simple implementation of a fsm:
struct _fsm
{
void (*ptr_to_fsm)(struct _fsm fsm);
char *data;
}
struct _fsm fsm;
fsm->ptr_to_fsm = start; // There is a function called start.
while (fsm->ptr_to_fsm != NULL)
{
fsm->ptr_to_fsm(&fsm);
}
void start (struct _fsm fsm)
{
if (fsm->data == NULL)
{
fsm->ptr_to_fsm = stop; // There is a function called stop.
}
/* Check more more conditions, and branch out on other functions based on the results. */
return;
}
void stop (struct _fsm fsm)
{
fsm->ptr_to_fsm = NULL; /* The while loop will terminate. */
/* And you're done (unless you have to do free`ing. */
}
I am working on a multithreaded client using C and the pthreads library, using a boss/worker arch design and am having issues understanding/debugging a stack-use-after-scope error that is causing my client to fail. (I am kinda new to C)
I have tried multiple things, including defining the variable globally, passing a double pointer reference, etc.
Boss logic within main:
for (i = 0; i < nrequests; i++)
{
struct Request_work_item *request_ctx = malloc(sizeof(*request_ctx));
request_ctx->server = server;
request_ctx->port = port;
request_ctx->nrequests = nrequests;
req_path = get_path(); //Gets a file path to work on
request_ctx->path = req_path;
steque_item work_item = &request_ctx; // steque_item is a void* so passing it a pointer to the Request_work_item
pthread_mutex_lock(&mutex);
while (steque_isempty(&work_queue) == 0) //Wait for the queue to be empty to add more work
{
pthread_cond_wait(&c_boss, &mutex);
}
steque_enqueue(&work_queue, work_item); //Queue the workItem in a workQueue (type steque_t, can hold any number of steque_items)
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&c_worker);
}
Worker logic inside a defined function:
struct Request_work_item **wi;
while (1)
{
pthread_mutex_lock(&mutex);
while (steque_isempty(&work_queue) == 1) //Wait for work to be added to the queue
{
pthread_cond_wait(&c_worker, &mutex);
}
wi = steque_pop(&work_queue); //Pull the steque_item into a Request_work_item type
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&c_boss);
char *path_to_file = (*wi)->path; //When executing, I get this error in this line: SUMMARY: AddressSanitizer: stack-use-after-scope
...
...
...
continues with additional worker logic
I expect the worker to pull the work_item from the queue, dereference the values and then perform some work. However, I keep getting AddressSanitizer: stack-use-after-scope, and the information for this error online is not very abundant so any pointers would be greatly appreciated.
The red flag here is that &request_ctx is the address of a local variable. It's not the pointer to the storage allocated with malloc, but the address of the variable which holds that storage. That variable is gone once this scope terminates, even though the malloc-ed block endures.
Maybe the fix is simply to delete the address-of & operator in this line?
steque_item work_item = &request_ctx; // steque_item is a void* so passing
// it a pointer to the Request_work_item
If we do that, then the comment actually tells the truth. Because otherwise we're making work_item a pointer to a pointer to the Request_work_item.
Since work_item has type void*, it compiles either way, unfortunately.
If the consumer of the item on the other end of the queue is extracting it as a Request_work_item *, then you not only have an access to an object that has gone out of scope, but also a type mismatch even if that object happens to still be in the producer's scope when the consumer uses it. The consumer ends up using a piece of the producer's stack as if it were a Request_work_item structure. Edit: I see that you are using a pointer-to-pointer when dequeuing the item and accessing it as (*wi)->path. Think about changing the design to avoid doing that. Or else, that wi pointer has to be dynamically allocated also, and freed. The producer has to do something like:
struct Request_work_item **p_request_ctx = malloc(sizeof *p_request_ctx);
struct Request_work_item *request_ctx = malloc(sizeof *request_ctx);
if (p_request_ctx && request_ctx) {
*p_request_ctx = request_ctx;
request_ctx->field = init_value;
// ... etc
// then p_request_ctx is enqueued.
The consumer then has to free the structure, and also free the pointer. That extra pointer just seems like pure overhead here; it doesn't provide any essential or useful level of indirection.
I would like to create a wrapper for c functions, so that I can convert a function call of the form ret = function(arg1,arg2,arg3); into the form /*void*/ function_wrapper(/*void*/);. That is similar to function objects in C++ and boost bind.
Is this possible? how can I do it?
Update:
To explain in more details what I am looking for:
We start with this function:
int f(int i){
//do stuff
return somevalue;
}
Obvioulsy, it is called like this:
// do stuff
int x = 0;
ret = f(0);
// do more stuff.
I would like to do some magic that will wrap the function into void function(void)
struct function_object fo;
fo.function_pointer = &f;
fo.add_arg(x, int);
fo.set_ret_pointer(&ret);
fo.call();
Note: I saw that there was a vote for closing this question and marking it as unclear. Please do not do that. I have a legitimate need to get this question answered. If you need explanation, ask and I will be glad to elaborate.
I came up with a better code that might allow you to do what you want. First I'll explain how it works, show the code and explain why I still don't think it's a good idea to use it (though the code might open doors for improvements that addresses those issues).
Functionality:
Before you start using the "function objects", you have to call an initialization function (FUNCTIONOBJ_initialize();), which will initialize the mutexes on every data structure used in the library.
After initializing, every time you want to call one of those "function objects", without using the parameters, you will have to set it up first. This is done by creating a FUNCTIONOBJ_handler_t pointer and calling get_function_handler(). This will search for a free FUNCTIONOBJ_handler data structure that can be used at the moment.
If none is found (all FUNCTIONOBJ_handler data structures are busy, being used by some function call) NULL is returned.
If get_function_handler() does find a FUNCTIONOBJ_handler data structure it will try to lock the FUNCTIONOBJ_id_holder data structure, that holds the ID of the FUNCTIONOBJ_handler of the function about to be called.
If FUNCTIONOBJ_id_holder is locked already, get_function_handler() will hang until it's unlocked by the thread using it.
Once FUNCTIONOBJ_id_holder is locked, the ID of the grabbed FUNCTIONOBJ_handler is wrote on it and the FUNCTIONOBJ_handler pointer is returned by get_function_handler.
With the pointer in hand, the user can set the pointer to the arguments and the return variable with set_args_pointer and set_return_pointer, which both take a void * as arguments.
Finally, you can call the function you want. It has to:
1 - Grab the FUNCTIONOBJ_handler ID from the FUNCTIONOBJ_id_holder data structure and use it to get a pointer to the FUNCTIONOBJ_handler itself.
2 - Use the FUNCTIONOBJ_handler to access the arguments.
3 - Return by using one of the return function (on the example we have ret_int, which will return an integer and unlock the FUNCTIONOBJ_handler)
Below is a simplified mind map describing a bit of what is going on:
Finally, the code:
funcobj.h:
#include <stdio.h>
#include <pthread.h>
#define MAX_SIMULTANEOUS_CALLS 1024
typedef struct {
//Current ID about to be called
int current_id;
//Mutex
pthread_mutex_t id_holder_mutex;
} FUNCTIONOBJ_id_holder_t;
typedef struct {
//Attributes
void *arguments;
void *return_pointer;
//Mutex
pthread_mutex_t handler_mutex;
} FUNCTIONOBJ_handler_t;
FUNCTIONOBJ_handler_t FUNCTIONOBJ_handler[MAX_SIMULTANEOUS_CALLS];
FUNCTIONOBJ_id_holder_t FUNCTIONOBJ_id_holder;
void set_return_pointer(FUNCTIONOBJ_handler_t *this, void *pointer);
void set_args_pointer(FUNCTIONOBJ_handler_t *this, void *pointer);
void ret_int(FUNCTIONOBJ_handler_t *this, int return_value);
void FUNCTIONOBJ_initialize(void);
FUNCTIONOBJ_handler_t *get_function_handler(void);
funcobj.c:
#include "funcobj.h"
void set_return_pointer(FUNCTIONOBJ_handler_t *this, void *pointer){
this->return_pointer = pointer;
}
void set_args_pointer(FUNCTIONOBJ_handler_t *this, void *pointer){
this->arguments = pointer;
}
void ret_int(FUNCTIONOBJ_handler_t *this, int return_value){
if(this->return_pointer){
*((int *) (this->return_pointer)) = return_value;
}
pthread_mutex_unlock(&(this->handler_mutex));
}
void FUNCTIONOBJ_initialize(void){
for(int i = 0; i < MAX_SIMULTANEOUS_CALLS; ++i){
pthread_mutex_init(&FUNCTIONOBJ_handler[i].handler_mutex, NULL);
}
pthread_mutex_init(&FUNCTIONOBJ_id_holder.id_holder_mutex, NULL);
}
FUNCTIONOBJ_handler_t *get_function_handler(void){
int i = 0;
while((0 != pthread_mutex_trylock(&FUNCTIONOBJ_handler[i].handler_mutex)) && (i < MAX_SIMULTANEOUS_CALLS)){
++i;
}
if(i >= MAX_SIMULTANEOUS_CALLS){
return NULL;
}
//Sets the ID holder to hold this ID until the function is called
pthread_mutex_lock(&FUNCTIONOBJ_id_holder.id_holder_mutex);
FUNCTIONOBJ_id_holder.current_id = i;
return &FUNCTIONOBJ_handler[i];
}
main.c:
#include "funcobj.h"
#include <string.h>
//Function:
void print(void){
//First the function must grab the handler that contains all its attributes:
//The FUNCTIONOBJ_id_holder is mutex locked, so we can just access its value and
//then free the lock:
FUNCTIONOBJ_handler_t *this = &FUNCTIONOBJ_handler[FUNCTIONOBJ_id_holder.current_id];
//We dont need the id_holder anymore, free it!
pthread_mutex_unlock(&FUNCTIONOBJ_id_holder.id_holder_mutex);
//Do whatever the function has to do
printf("%s\n", (char *) this->arguments);
//Return the value to the pointed variable using the function that returns an int
ret_int(this, 0);
}
void *thread_entry_point(void *data){
int id = (int) data;
char string[100];
snprintf(string, 100, "Thread %u", id);
int return_val;
FUNCTIONOBJ_handler_t *this;
for(int i = 0; i < 200; ++i){
do {
this = get_function_handler();
} while(NULL == this);
set_args_pointer(this, string);
set_return_pointer(this, &return_val);
print();
}
return NULL;
}
int main(int argc, char **argv){
//Initialize global data strucutres (set up mutexes)
FUNCTIONOBJ_initialize();
//testing with 20 threads
pthread_t thread_id[20];
for(int i = 0; i < 20; ++i){
pthread_create(&thread_id[i], NULL, &thread_entry_point, (void *) i);
}
for(int i = 0; i < 20; ++i){
pthread_join(thread_id[i], NULL);
}
return 0;
}
To compile: gcc -o program main.c funcobj.c -lpthread
Reasons to avoid it:
By using this, you are limiting the number of "function objects" that can be running simultaneously. That's because we need to use global data structures to hold the information required by the functions (arguments and return pointer).
You will be seriously slowing down the program when using multiple threads if those use "function objects" frequently: Even though many functions can run at the same time, only a single function object can be set up at a time. So at least for that fraction of time it takes for the program to set up the function and actually call it, all other threads trying to run a function will be hanging waiting the the data structure to be unlocked.
You still have to write some non-intuitive code at the beginning and end of each function you want to work without arguments (grabbing the FUNCTIONOBJ_handler structure, unlocking the FUNCTIONOBJ_id_holder structure, accessing arguments through the pointer you grabbed and returning values with non-built-in functions). This increases the chances of bugs drastically if care is not taken, specially some nasty ones:
Increases the chances of deadlocks. If you forget to unlock one of the data structures in any point of your code, you might end up with a program that works fine at some moments, but randomly freeze completely at others (because all function calls without arguments will be hanging waiting for the lock to be freed). That is a risk that happens on multithreaded programs anyways, but by using this you are increasing the amount of code that requires locks unnecessarily (for style purposes).
Complicates the use of recursive functions: Every time you call the function object you'll have to go through the set up phrase (even when inside another function object). Also, if you call the recursive function enough times to fill all FUNCTIONOBJ_handler structures the program will deadlock.
Amongst other reasons I might not notice at the moment :p
I am understanding and implementing the concept of threading in my application. Since now things are going good. But I have few questions still unanswered and they are making me slow now. I would appreciate if anyone replies to even any of them
In Createthread(), can we only take 1 argument? as I have seen in MSDN website and all other examples that I have seen I saw only 1 argument, LPVOID.
The other thing is , what does the return value DWORD WINAPI means as a return value? Can we have only DWORD , int or any other return type. I suppose it has something to do with HANDLE (may be)
I want to use the array of the thread, hence I learn the array to functions, and (as I have understood) threads are itself just a function called by CreateThread() routine, hence I tried to implement that concept there but could not because of the return type DWORD WINAPI was not allowing me to do so?
I have one single thread for saving files, now I want its array so that I can save multiple files at the same time (not exaclty the same starting time, but sort of parallel file saving). How can I do that?
Thanks
Shan
Indeed, you can only take one argument, of type void * (LPVOID).
However, since it can point to anything, it can point to a struct
or object (usually allocated on the heap for lifetime reasons).
WINAPI is not part of the return value, it's the function's calling
convention. The function must return a DWORD or anything that fit
in it. It must NOT return a pointer, because a pointer can't fit a
DWORD in Win64.
I don't understand, please elaborate what you're
trying to do.
Usually for this you need a single thread function,
passed several times to CreateThread() with a different argument
each time. Don't forget to keep the thread handles (which you'll
likely save in an array) until you stop needing them and close them
with CloseHandle().
for the point number three I guess I understood and will try differently. I was using
DWORD WINAPI save_uwpi_file0( LPVOID )
{
while(1)
{
if(release == 1 && flag_oper1 == 1)
{
int w_cnt = 0; FILE *opfile;
char fname[30] = "txt_file0.txt";
//opening file for write
opfile = fopen(fname , "w");
printf("assigning memory for file 1 \n");
ssint *Lmem = (ssint *)malloc( sizeof(ssint)*size_of_memory);
memcpy(Lmem, pInDMA, sizeof(ssint)*size_of_memory);
release = 0;
printf("relseaing for second file saving\n");
for( int nbr = 0; nbr < size_of_memory; nbr++){
fprintf(opfile , "%hi\n", Lmem[nbr] );
}
printf("aligned free 1\n");
free(Lmem);
fclose(opfile);
printf("File saved 1\n\n");
return 1;
} //if statement ends
}
}
and I was using following to make the pointer to (thread) function
DWORD WINAPI (* save_uwpi_file0)(LPVOID);
I guess I should try something like
DWORD (* save_uwpi_file0)(LPVOID);
I will do it and post the result here
I have a legacy C Linux application that I need to reuse . This application uses a lot of global variables. I want to reuse this application's main method and invoke that in a loop. I have found that when I call the main method( renamed to callableMain) in a loop , the application behavior is not consistent as the values of global variables set in previous iteration impact the program flow in the new iteration.
What I would like to do is to reset all the global variables to the default value before the execution of the the new iteration.
for example , the original program is like this
OriginalMain.C
#include <stdio.h>
int global = 3; /* This is the global variable. */
void doSomething(){
global++; /* Reference to global variable in a function. */
}
// i want to rename this main method to callableMain() and
// invoke it in a loop
int main(void){
if(global==3) {
printf(" All Is Well \n");
doSomething() ;
}
else{
printf(" Noooo\n");
doNothing() ;
}
return 0;
}
I want to change this program as follows:
I changed the above file to rename the main() to callableMain()
And my new main methods is as follows:
int main(){
for(int i=0;i<20;i++){
callableMain();
// this is where I need to reset the value of global vaiables
// otherwise the execution flow changes
}
}
Is this possible to reset all the global variables to the values before main() was invoked ?
The short answer is that there is no magical api call that would reset global variables. The global variables would have to be cached and reused.
I would invoke it as a subprocess, modifying its input and output as needed. Let the operating system do the dirty work for you.
The idea is to isolate the legacy program from your new program by relegating it to its own process. Then you have a clean separation between the two. Also, the legacy program is reset to a clean state every time you run it.
First, modify the program so that it reads the input data from a file, and writes its output in a machine-readable format to another file, with the files being given on the command line.
You can then create named pipes (using the mkfifo call) and invoke the legacy program using system, passing it the named pipes on the command line. Then you feed it its input and read back its output.
I am not an expert on these matters; there is probably a better way of doing the IPC. Others here have mentioned fork. However, the basic idea of separating out the legacy code and invoking it as a subprocess is probably the best approach here.
fork() early?
You could fork(2) at some early point when you think the globals are in a good state, and then have the child wait on a pipe or something for some work to do. This would require writing any changed state or at least the results back to the parent process but would decouple your worker from your primary control process.
In fact, it might make sense to fork() at least twice, once to set up a worker controller and save the initialized (but not too initialized :-) global state, and then have this worker controller fork() again for each loop you need run.
A simpler variation might be to just modify the code so that the process can start in a "worker mode", and then use fork() or system() to start the application at the top, but with an argument that puts it in to the slave mode.
There is a way to do this on certain platforms / compilers, you'd basically be performing the same initialization your compiler performs before calling main().
I have done this for a TI DSP, in that case I had the section with globals mapped to a specific section of memory and there were linker directives available that declared variables pointing to the start and end of this section (so you can memset() the whole area to zero before starting initialization). Then, the compiler provided a list of records, each of which comprised of an address, data length and the actual data to be copied into the address location. So you'd just loop through the records and do memcpy() into the target address to initialize all globals.
Very compiler specific, so hopefully the compiler you're using allows you to do something similar.
In short, no. What I would do in this instance is create definitions, constants if you will, and then use those to reset the global variables with.
Basically
#define var1 10
int vara = 10
etc... basic C right?
You can then go ahead and wrap the reinitialization in a handy function =)
I think you must change the way you see the problem.
Declare all the variables used by callableMain() inside callableMain()'s body, so they are not global anymore and are destroyed after the function is executed and created once again with the default values when you call callableMain() on the next iteration.
EDIT:
Ok, here's what you could do if you have the source code for callableMain(): in the beginning of the function, add a check to verify if its the first time the function its being called. Inside this check you will copy the values of all global variables used to another set of static variables (name them as you like). Then, on the function's body replace all occurences of the global variables by the static variables you created.
This way you will preserve the initial values of all the global variables and use them on every iteration of callableMain(). Does it makes sense to you?
void callableMain()
{
static bool first_iter = true;
if (first_iter)
{
first_iter = false;
static int my_global_var1 = global_var1;
static float my_global_var2 = global_var2;
..
}
// perform operations on my_global_var1 and my_global_var2,
// which store the default values of the original global variables.
}
for (int i = 0; i < 20; i++) {
int saved_var1 = global_var1;
char saved_var2 = global_var2;
double saved_var3 = global_var3;
callableMain();
global_var1 = saved_var1;
global_var2 = saved_var2;
global_var3 = saved_var2;
}
Or maybe you can find out where global variables start memcpy them. But I would always cringe when starting a loop ...
for (int i = 0; i < 20; i++) {
static unsigned char global_copy[SIZEOFGLOBALDATA];
memcpy(global_copy, STARTOFGLOBALDATA, SIZEOFGLOBALDATA);
callableMain();
memcpy(STARTOFGLOBALDATA, global_copy, SIZEOFGLOBALDATA);
}
If you don't want to refactor the code and encapsulate these global variables, I think the best you can do is define a reset function and then call it within the loop.
Assuming we are dealing with ELF on Linux, then the following function to reset the variables works
// these extern variables come from glibc
// https://github.com/ysbaddaden/gc/blob/master/include/config.h
extern char __data_start[];
extern char __bss_start[];
extern char _end[];
#define DATA_START ((char *)&__data_start)
#define DATA_END ((char *)&__bss_start)
#define BSS_START ((char *)&__bss_start)
#define BSS_END ((char *)&_end)
/// first call saves globals, subsequent calls restore
void reset_static_data();
// variable for quick check
static int pepa = 42;
// writes to memory between global variables are reported as buffer overflows by asan
ATTRIBUTE_NO_SANITIZE_ADDRESS
void reset_static_data()
{
// global variable, ok to leak it
static char * x;
size_t s = BSS_END - DATA_START;
// memcpy is always sanitized, so access memory as chars in a loop
if (x == NULL) { // store current static variables
x = (char *) malloc(s);
for (size_t i = 0; i < s; i++) {
*(x+i) = *(DATA_START + i);
}
} else { // restore previously saved static variables
for (size_t i = 0; i < s; i++) {
*(DATA_START + i) = *(x+i);
}
}
// quick check, see that pepa does not grow in stderr output
fprintf(stderr, "pepa: %d\n", pepa++);
}
The general approach is based on answer in How to get the data and bss address space in run time (In Unix C program), see the linked ysbaddaden/gc GitHub repo for macOS version of the macros.
To test the above code, just call it a few times and note that the incremented global variable pepa still keeps the value of 42.
reset_static_data();
reset_static_data();
reset_static_data();
Saving current state of the globals is convenient in that it does not require rerunning __attribute__((constructor)) functions which would be necessary if I set everything in .bss to zero (which is easy) and everything in .data to the initial values (which is not so easy). For example, if you load libpython3.so in your program, it does do run-time initialization which is lost by zeroing .bss. Calling into Python then crashes.
Sanitizers
Writing into areas of memory immediately before or after a static variable will trigger buffer-overflow warning from Address Sanitizer. To prevent this, use the ATTRIBUTE_NO_SANITIZE_ADDRESS macro the way the code above does. The macro is defined in sanitizer/asan_interface.h.
Code coverage
Code coverage counters are implemented as global variables. Therefore, resetting globals will cause coverage information to be forgotten. To solve this, always dump the coverage-to-date before restoring the globals. There does not seem to be a macro to detect whether code coverage is enabled or not in the compiler, so use your build system (CMake, ...) to define suitable macro yourself, such as QD_COVERAGE below.
// The __gcov_dump function writes the coverage counters to gcda files
// and the __gcov_reset function resets them to zero.
// The interface is defined at https://github.com/gcc-mirror/gcc/blob/7501eec65c60701f72621d04eeb5342bad2fe4fb/libgcc/libgcov-interface.c
extern "C" void __gcov_reset();
extern "C" void __gcov_dump();
void flush_coverage() {
#if defined(QD_COVERAGE)
__gcov_dump();
__gcov_reset();
#endif
}