In a signal handler, I'm changing the value of a variable. However, the program never notices the update, even though I've declared the variable leader_barrier as sig_atomic_t.
void timer_action(int signum)
{
static int count = 0;
if ( !(*pbarrier_in_proc) && !(leader_barrier) && !(*pno_more) )
leader_barrier = 1;
}
And its confirmed that timer_action does execute and leader_barrier does become 1 inside it, as I have seen it by printing its values inside the signal handler.
You should declare leader_barrier as volatile sig_atomic_t, not just sig_atomic_t. Otherwise the compiler is free to assume the variable does not change asynchronously. That is, it may read it once at the start of the function (say) and, assuming no other functions that could change leaderboard get called, it need not read it again.
Maybe the two variables are not the same variable. Try printing their addresses in both the signal handler and the other code in question.
Related
I do not understand why in the function middleFunc(), a segmentation fault is raisen when entry_point(arg) is invoked inside the if ( setjmp(middle) ) statement.
#include <stdio.h>
#include <setjmp.h>
jmp_buf start,middle,end;
void finalFunc(void *v)
{
printf("hello\n");
return ;
}
void middleFunc(void (*entry_point)(void *), void *arg)
{
//just debug : this does not cause segmentation fault
entry_point(arg);
if ( setjmp(middle) ){
//this casues the segmentation fault
entry_point(arg);
//once the entry point (finalFunc) is executed go to jmp_buffer end
longjmp(end,1);
}
else {
longjmp(start,1);
}
}
int main(){
if (setjmp(end)){
//exit since finalFunc has been executed
return 0;
}
if (setjmp(start)){
//the middleFunc has previously set the jmp_buffer middle
longjmp(middle,1);
}
else{
int x = 1;
middleFunc(finalFunc,(void*)&x);
}
}
In your code the behavior is undefined. You are not allowed to long-jump to middle after middleFunc finished execution (either by normal completion or by another longjmp).
7.13.2.1 The longjmp function
2 The longjmp function restores the environment saved by the most recent invocation of the setjmp macro in the same invocation of the program with the corresponding jmp_buf argument. If there has been no such invocation, [...] or if the function containing the invocation of the setjmp macro has terminated execution248) in the interim [...] the behavior is undefined.
248) For example, by executing a return statement or because another longjmp call has caused a transfer to a setjmp invocation in a function earlier in the set of nested calls.
In your code middleFunc sets up middle and after that immediately exits to main by doing longjmp(start,1). After that jump middle is no longer valid. You are no longer allowed to jump to middle from anywhere. setjmp/longjmp mechanism only supports jumps up the call stack. You cannot do side-jumps or down-jumps. Only up-jumps are supported.
From the practical point of view, you are attempting to jump into a "dead" function invocation and somehow expecting that function parameter values are still valid (like, preserved from the previous invocation or something). But they are not. setjmp/longjmp do not preserve/restore parameter values. Value of entry_point in that "dead" invocation is probably some garbage. When you attempt to make a call through entry_point, the code coredumps.
P.S. It is true that side-jumping with setjmp/longjmp is sometimes used to implement co-routines. However, such usage falls outside the boundaries of standard library specification. And in any case such usage will never expect preservation of parameter values.
I am trying register one function with atexit () that will print different messages based off of the current status of the program. I know that when you register the function with atexit you cannot pass an argument.
So, how can you pass the program status, say an integer, and make that function print different statements?
I know that I can register multiple functions, but I have to only use one.
Instead of using atexit, make use of the on_exit function which takes the status passed into exit() as one argument, and a void * that you can pass in.
int on_exit(void (*function)(int , void *), void *arg);
The on_exit() function registers the given function to be called at
normal process termination, whether via exit(3) or via return from the
program's main(). The function is passed the status argument given to
the last call
to exit(3) and the arg argument from on_exit().
The same function may be registered multiple times: it is called once for each registration.
When a child process is created via fork(2), it inherits copies of its parent's registrations. Upon a successful call to one of the
exec(3) functions, all registrations are removed.
Use a global variable. That can be read by your function registered with atexit.
Here's a different idea. Instead of using a global variable or different atexit handlers, you could use a simplr exit wrapper that prints
the desired message and then calls exit.
void my_exit(int rc)
{
/* Assuming you have enum constants ERR_1, etc,
* with expected error codes and 0 isn't an error condition. */
switch(rc) {
case ERR_1:
/* print message */
break;
case ERR_2:
/* print message */
break;
...
}
exit(rc);
}
Instead of ERR_1, etc, you could directly use integer constants or use if-else statements. Now you can pass the exit code to my_exit and use it wherever you'd use exit(). You would call it at the end of main() too with my_exit(0).
I have a program with multiple threads.
In my main thread I examine in a permanent loop whether a global variable has the value 1.
This variable I set during the runtime in the other thread with a Mutex locked on it to 1.
So the if condition should be true in the main thread. But it doesn't work... But if i put a printf before the if condition it works. This is so weird I have no idea whats wrong. Thanks
The code:
while(1)
{
printf("\n");
if(logging_active == 1) {
//check filesize every 30s. If logfile size over 1MB (1.000.000) send file
if((timestamp_realtime_sec() - last_time) >= ((logtime+1))) {
printf("check filesize...\n");
if(fileSize("log") > 100000) {
logfileHandler("log");
}
last_time = timestamp_realtime_sec();
}
}
}
Output:
check filesize ...
Without the printf it's output nothing.
Solution for me:
changing the variable declaration from int logging_active to volatile int logging_active solved the problem.
I am assuming you are locking mutex and updating logging_active in other thread. You should lock the same mutex and do the check in current thread.
pthread_mutex_lock(mutex);
while(logging_active == 0) {
pthread_mutex_unlock(mutex)
sleep(SOME_TIME);
}
pthread_mutex_unlock(mutex)
//Your code
}
But I recommend you to use condition variables.
The compiler doesn't know you're updating the variable from another thread, so it may not be actually checking it every time. Mark the variable as volatile and it should work as you expect. This tells the compiler that it isn't allowed to omit loads from that variable--it really has to read it every time.
I have a simple apache web server with a hook function and a handler function.
int globalVar1;
int globalVar2;
static void register_hooks(apr_pool_t *pool)
{
globalVar1 = 9; /* or any other value... */
/* Create a hook in the request handler, so we get called when a request arrives */
ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST);
}
static int example_handler(request_rec *r)
{
printf("globalVar1=%d", globalVar1); /* print 9 */
globalVar2 = 9; /* or any other value... */
printf("globalVar2=%d", globalVar2); /* sometimes print 9 and sometimes not - race condition. */
/* do something... */
return OK;
}
I noticed that when I initialize globalVar1 in the hook, the variable has the same value as I initialized in the hook,
although the hook and the handler are been called on different processes.
1. what is the reason for that kind of behavior?
As a result, I decided to move the variable initialization to the handler function (globalVar2).
The problem I noticed is happening when the handler gets 2 requests at the same time and therefore the variable is not being initialized correctly.
So if I want to avoid race condition, I need to use lock on the variable initialization, but if I want to use lock, I need to initialize the lock before
and again I have the problem of initialization in multi threaded system.
2. How can I use lock in this kind of situation?
By mentioning variable initialization, I mean any initialization, even calling another function to initialize a global struct.
It could be much easier if I could share memory between the two processes (hook and handler), but from the investigation I did - it is impossible.
To make sure the initialization is done only once in a multithreaded situation, use a function CallOnce, that internally makes sure it is called exactly once.
For example: C11 threads.h call_once, or pthread_once.
I am trying to implement a user level thread library and need to schedule threads in a round robin fashion. I am currently trying to make switching work for 2 threads that I have created using makecontext, getcontext and swapcontext. setitimer with ITIMER_PROF value is used and sigaction is assigned a handler to schedule a new thread whenever the SIGPROF signal is generated.
However, the signal handler is not invoked and the threads therefore never get scheduled. What could be the reason? Here are some snippets of the code:
void userthread_init(long period){
/*long time_period = period;
//Includes all the code like initializing the timer and attaching the signal
// handler function "schedule()" to the signal SIGPROF.
// create a linked list of threads - each thread's context gets added to the list/updated in the list
// in userthread_create*/
struct itimerval it;
struct sigaction act;
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = &schedule;
sigemptyset(&act.sa_mask);
sigaction(SIGPROF,&act,NULL);
time_period = period;
it.it_interval.tv_sec = 4;
it.it_interval.tv_usec = period;
it.it_value.tv_sec = 1;
it.it_value.tv_usec = 100000;
setitimer(ITIMER_PROF, &it,NULL);
//for(;;);
}
The above code is to initialize a timer and attach a handler schedule to the signal handler. I am assuming the signal SIGPROF will be given to the above function which will invoke the scheduler() function. The scheduler function is given below:
void schedule(int sig, siginfo_t *siginf, ucontext_t* context1){
printf("\nIn schedule");
ucontext_t *ucp = NULL;
ucp = malloc(sizeof(ucontext_t));
getcontext(ucp);
//ucp = &sched->context;
sched->context = *context1;
if(sched->next != NULL){
sched = sched->next;
}
else{
sched = first;
}
setcontext(&sched->context);
}
I have a queue of ready threads in which their respective contexts are stored. Each thread should get scheduled whenever setcontext instruction is executed. However, scheduler() is not invoked! Can anyone please point out my mistake??
Completely revising this answer after looking at the code. There are a few issues:
There are several compiler warnings
You are never initializing your thread ID's, not outside or inside your thread creation method, so I'm surprised the code even works!
You are reading from uninitialized memory in your gtthread_create() function, I tested on both OSX & Linux, on OSX it crashes, on Linux by some miracle it's initialized.
In some places you call malloc(), and overwrite it with a pointer to something else - leaking memory
Your threads don't remove themselves from the linked list after they've finished, so weird things are happening after the routines finish.
When I add in the while(1) loop, I do see schedule() being called and output from thread 2, but thread 1 vanishes into fat air (probably because of the uninitialized thread ID). I think you need to have a huge code cleanup.
Here's what I'd suggest:
Fix ALL of your compiler warnings — even if you think they don't matter, the noise may lead to you missing things (such as incompatible pointer types, etc). You're compiling with -Wall & -pedantic; that's a good thing - so now take the next step & fix them.
Put \n at the END of your printf statements, not the start — The two threads ARE outputting to stdout, but it's not getting flushed so you can't see it. Change your printf("\nMessage"); calls to printf("Message\n");
Use Valgrind to detect memory issues — valgrind is the single most amazing tool you will ever use for C/C++ development. It's available through apt-get & yum. Instead of running ./test1, run valgrind ./test1 and it will highlight memory corruption, memory leaks, uninitialized reads, etc. I can't stress this enough; Valgrind is amazing.
If a system call returns a value, check it — in your code, check the return values to all of getcontext, swapcontext, sigaction, setitimer
Only call async-signal-safe methods from your scheduler (or any signal handler) — so far you've fixed malloc() and printf() from inside your scheduler. Check out the signal(7) man page - see "Async-signal-safe functions"
Modularize your code — your linked list implementation could be tidier, and if it was separated out, then 1) your scheduler would have less code & be simpler, and 2) you can isolate issues in your linked list without having to debug scheduler code.
You're almost there, so keep at it - but keep in mind these three simple rules:
Clean as you go
Keep the compiler warnings fixed
When weird things are happening, use valgrind
Good luck!
Old answer:
You should check the return value of any system call. Whether or not it helps you find the answer, you should do it anyway :)
Check the return value of sigaction(), if it's -1, check errno. sigaction() can fail for a few reasons. If your signal handler isn't getting fired, it's possible it hasn't been set up.
Edit: and make sure you check the return of setitimer() too!
Edit 2: Just a thought, can you try getting rid of the malloc()? malloc is not signal safe. eg: like this:
void schedule(int sig, siginfo_t *siginf, ucontext_t* context1){
printf("In schedule\n");
getcontext(&sched->context);
if(sched->next != NULL){
sched = sched->next;
}
else{
sched = first;
}
setcontext(&sched->context);
}
Edit 3: According to this discussion, you can't use printf() inside a signal handler. You can try replacing it with a call to write(), which is async-signal safe:
// printf("In schedule\n");
const char message[] = "In schedule\n";
write( 1, message, sizeof( message ) );