I'm currently using an alarm signal SIGALRM to exit from an infinite loop.
My code is structured as follows
main_loop() {
set_alarm();
while(1)
counter++;
}
The logic is
- Set an alarm
- Enter while loop
- Read counter when we get SIGALRM
The code that runs upon SIGALRM is given below:
VERBOSE("Cycles :%u\n", counter);
iteration_index++;
if(iteration_index == iterations)
exit(0);
counter = 0;
main_loop();
I would now like to now give the user an option to specify the number of times (iterations) the alarm should go off. In short, modify the above logic into:
- Set an alarm
- Enter while loop
- Read counter when we get SIGALRM
- Increment iteration_index
-If iteration_index < iterations: call main_loop
- Else exit
I implemented the above logic and found that it segfaults after a few thousand iterations. I believe that the reason for this is that:
When the alarm triggers and it makes a new call to main_loop, the original main_loop frame still exists. This keeps repeatedly happening until it runs out of space and throws a segfault.
I've tried coming up with some design that does what I want, but I'm unable to visualize code-flow after the signal is triggered.
What is the right way to implement what I've described?
Regrading the modifications you listed:
- Set an alarm
- Enter while loop
- Read counter when we get SIGALRM
- Increment iteration_index
- If iteration_index < iterations: call main_loop
- Else exit
You could provide a series of keystrokes (say <ctrl> - 1 to allow the user to specify a number of times (just once). This example runs (with delays to allow some time for GetAsyncKeys(). Until the user presses <ctrl> 1, the loop will run forever. When <ctrl> 1 is pressed, program prompts them with how many time to let the alarm sound, then programs runs that many iterations, then quits..
#include <stdio.h>
#include <windows.h>
void set_alarm(void);
int main(void) {
int iterations=-1, counter=0;
while (iterations != counter)
{
if(iterations == -1)//code will run forever if iteration is not set by user
{
set_alarm();
counter++;
if (GetAsyncKeyState(VK_CONTROL)<0)
{
if (GetAsyncKeyState('1')<0)
{
printf("Enter how many time alarm should activate:\n");
scanf("%d", &iterations);
counter = 0;
Sleep(10);
}
}
}
else//this block will monitor alarm count, program quits when limit reached.
{
if(counter < iterations)
{
set_alarm();
counter++;
}
}
Sleep(10);//changed here for my test, you might need to change again
}
return 0;
}
void set_alarm(void)
{
//do something;
}
Yes, you are right. When the handler for SIGALRM runs, the main_loop() function is still running. Both functions will in fact be running on the same thread. If you never exit from the SIGALRM handler, then the next handler will go on top, and this will keep happening until you run out of stack and crash.
To fix this, simply return from the signal handler.
// Make sure that both of these are volatile
volatile int iteration_index;
volatile int counter;
void catch_sigalrm(int signo)
{
// Note: this is not safe, so I commented it out
// VERBOSE("Cycles :%u\n", counter);
iteration_index++;
if(iteration_index == iterations)
exit(0);
counter = 0;
set_alarm();
}
void main_loop(void)
{
set_alarm();
while (1)
__sync_fetch_and_add(&counter, 1);
}
I think this will work. It should use ldrex and strex for incrementing counter.
The problem with using counter++ is that it can be interrupted: counter++ is actually something like this:
int old_value = counter; // memory access
int new_value = old_value + 1;
counter = new_value; // memory access
As you can see, if the alarm goes off in the middle of counter++ the results will get wiped out. That is why you need to use __sync_fetch_and_add() instead.
The volatile specifier is MANDATORY
Here's the main loop with a normal counter variable. I've removed the call to set_alarm() because we're not concerned about it right now.
// This is wrong
int counter;
void main_loop()
{
while (1)
counter++;
}
Here's the assembly:
_main_loop:
b _main_loop
.comm _counter, 4, 2
Wait a second! It doesn't increment anything, it's just an infinite loop!
That's right. The compiler detected that counter can not possibly be read anywhere, and so optimized the increment right out of existence. You MUST use volatile. The volatile keyword instructs the compiler that counter may be read or written by something else that is not a thread (actually, it instructs the compiler to be strict about loads and stores, but that's the technical version). (For working with threads, volatile is almost never useful, you have to use atomics which are different.)
Here's the version with volatile:
// This is ALSO wrong
volatile int counter;
void main_loop(void)
{
while (1) counter++;
}
And the assembly:
_main_loop:
; load address of counter into r0
...
loop:
; increment counter
ldr r1, [r0]
adds r1, #1
str r1, [r0]
b loop
As you can see, this can be interrupted in the middle. This is why you have to use __sync_fetch_and_add(): it detects when counter++ was interrupted and it restarts the operation from the beginning.
Here is the correct version:
// MUST be volatile
volatile int counter;
void main_loop(void)
{
while (1)
__sync_fetch_and_add(&counter, 1);
}
More notes
You can't call printf() in a signal handler.
In fact, try to avoid doing anything in a signal handler.
At most, set a flag, write a byte to a pipe, or something like that.
Related
I have a main thread which create child threads to do various task. There is a child thread which is tasked to report on the status every 100s
My current mechanism of stopping the thread is to observe a global boolean. Somewhat like this
Child thread
void* ReportThread(bool* operation)
{
while(*operation)
{
// do its reporting task
// ........
int counter = 0;
while( counter < 100 && operation )
{
// let it sleep for 1 seconds and wake up to check
sleep(1);
sleepCounter += 1;
}
}
}
Parent (Main) Thread:
bool operation = false;
int main(){
pthread_t tid;
err = pthread_create(&tid), NULL, &ReportThread, &operation);
printf("Please input esc to end operation \n");
while ((ch = getchar()) != 27);
operation =true;
pthread_join(tid,NULL);
return 0;
}
The problem:
It seem that using sleep(n). The number of seconds seem very inconsistent. When the program is stopped, this thread takes a while maybe 10 second to actually stop
Is there a way to interrupt a thread to sleep? I heard you could use signal. I am coding in linux
Can I just simply just use a pthread_cancel(tid) instead of pthread_join(tid)?
Regards
This part
while( counter < 100 || operation )
{
// let it sleep for 1 seconds and wake up to check
sleep(1);
sleepCounter += 1;
}
is wrong.
First I assume that sleepCounter += 1; is really a typo and that it should be:
while( counter < 100 || operation )
{
// let it sleep for 1 seconds and wake up to check
sleep(1);
counter += 1;
}
Then the problem is that even if operation is set to false by some other thread, the while will not finish until counter reach 100.
The code should be
while( counter < 100 && operation )
{
// let it sleep for 1 seconds and wake up to check
sleep(1);
counter += 1;
}
Further, in main you never set operation to false. Another typo?
You don't need two while loops. And if you want to set a timer, use time functions for it, because sleep is a cancellation point and it is not guaranteed that sleep actually sleeps that amount of time.
Example:
void* ReportThread(void *args)
{
time_t start = time(NULL);
time_t now;
bool *operation = (bool*) args;
while (*operation) { //while active
now = time(NULL); //get current time
if (now - start >= 100) { //if the threshold is exceeded
start = now; //reset timer
//and probably do other stuff
}
sleep(1); //sleep for one second
}
return NULL;
}
The example above has a max lag of one second, that means if you set operation to false right at that moment when the thread entered the sleep state, you have to wait until sleep returns, only then it will recognize the modified state. The example also has the advantage, that you can easily modify the threshold value (since it depends on the 'real' time, instead of a counter and a non accurate sleep time).
Btw. the variable operation should be either an atomic boolean or protected by a mutex (since it is accessed from different threads).
To answer the questions of your problem:
should be answered by the example above
since i mentioned it before, sleep is a cancellation point, that means it gets interrupted if the process handles a signal (see man pthreads - section Cancellation points).
see man pthread_cancel - section Notes
On Linux, cancellation is implemented using signals. Under the NPTL threading implementation, the first real-time signal (i.e., signal 32) is used for this purpose. On LinuxThreads, the second real-time signal is used, if real-time signals are available, otherwise SIGUSR2 is used.
You cannot use pthread_cancel over pthread_join! You have to use pthread_join in either case (described in detail in the man page).
I don't know if this will fix all your problems, but it's a bit too much for a comment. One problem, your ReportThread function signature is wrong. It should be:
void* ReportThread(void* args);
And then in that function you need to do something like:
void* ReportThread(void* args)
{
bool* operation = (bool*)args;
while(*operation)
{
...
}
}
I'm not sure how it's working right now, but your compiler should at least be issuing a warning trying to convert a bool* type to a bool.
Also be aware of race conditions on operation
I'm taking an operating system class and my professor gave us this homework.
"Place __asm mfence in a proper position."
This problem is about using multiple threads and its side-effect.
Main thread is increasing shared_var but thread_1 is doing it in the same time.
Thus, shared_var becomes 199048359.000 when the code is increasing number 2000000 times.
The professor said __asm mfence will solve this issue. But, I do not know where to place it.
I'm trying to search the problem on google, github and here but I cannot find a source.
I do not know this is a stupid question because I'm not majoring in computer science.
Also, I would like to know why this code shows 199948358.0000 not 2000000.00
Any help would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
int turn;
int interested[2];
void EnterRegion(int process);
void LeaveRegion(int process);
DWORD WINAPI thread_func_1(LPVOID lpParam);
volatile double shared_var = 0.0;
volatile int job_complete[2] = {0, 0};
int main(void)
{
DWORD dwThreadId_1, dwThrdParam_1 = 1;
HANDLE hThread_1;
int i, j;
// Create Thread 1
hThread_1 = CreateThread(
NULL, // default security attributes
0, // use default stack size
thread_func_1, // thread function
&dwThrdParam_1, // argument to thread function
0, // use default creation flags
&dwThreadId_1
); // returns the thread identifier
// Check the return value for success.
if (hThread_1 == NULL)
{
printf("Thread 1 creation error\n");
exit(0);
}
else
{
CloseHandle( hThread_1 );
}
/* I am main thread */
/* Now Main Thread and Thread 1 runs concurrently */
for (i = 0; i < 10000; i++)
{
for (j = 0; j < 10000; j++)
{
EnterRegion(0);
shared_var++;
LeaveRegion(0);
}
}
printf("Main Thread completed\n");
job_complete[0] = 1;
while (job_complete[1] == 0) ;
printf("%f\n", shared_var);
_getch();
ExitProcess(0);
}
DWORD WINAPI thread_func_1(LPVOID lpParam)
{
int i, j;
for (i = 0; i < 10000; i++) {
for (j = 0; j < 10000; j++)
{
EnterRegion(1);
shared_var++;
LeaveRegion(1);
}
}
printf("Thread_1 completed\n");
job_complete[1] = 1;
ExitThread(0);
}
void EnterRegion(int process)
{
_asm mfence;
int other;
other = 1 - process;
interested[process] = TRUE;
turn = process;
while (turn == process && interested[other] == TRUE) {}
_asm mfence;
}
void LeaveRegion(int process)
{
_asm mfence;
interested[process] = FALSE;
_asm mfence;
}
The EnterRegion() and LeaveRegion() functions are implementing a critical region using a thing called "Peterson's algorithm".
Now, the key to Peterson's algorithm is that when a thread reads turn it must get the latest (most recent) value written by any thread. That is, operations on turn must be Sequentially Consistent. Also, the write to interested[] in EnterRegion() must become visible to all threads before (or at the same time) as the write to turn.
So the place to put the mfence is after the turn = process ; -- so that the thread does not proceed until its write to turn is visible to all other threads.
It is also important to persuade the compiler to read from memory every time it reads turn and interested[], so you should set them volatile.
If you are writing this for x86 or x86_64, that is sufficient -- because they are generally "well behaved", so that:
all the writes to turn and interested[process] will occur in program order
all the reads of turn and interested[other] will also occur in program order
and setting those volatile ensures that the compiler doesn't fiddle with the order, either.
The reason for using the mfence on the x86 and x86_64 in this case is to flush the write queue to memory before proceeding to read the turn value. So, all memory writes go into a queue, and at some time in the future each write will reach actual memory, and the effect of the write will become visible to other threads -- the write has "completed". Writes "complete" in the same order the program did them, but delayed. If the thread reads something it has written recently, the processor will pick the (most recent) value out of the write queue. This means that the thread does not need to wait until the write "completes", which is generally a Good Thing. However, it does mean that the thread is not reading the same value that any other thread will read, at least until the write does "complete". What the mfence does is to stall the processor until all outstanding writes have "completed" -- so any following reads will read the same thing any other thread would read.
The write to interested[] in LeaveRegion() does not (on x86/x86_64) require an mfence, which is good because mfence is a costly operation. Each thread only ever writes to its own interested[] flag and only ever reads the other's. The only constraint on this write is that it must not "complete" after the write in EnterRegion() (!). Happily the x86/x86_64 does all writes in order. [Though, of course, after the write in LeaveRegion() the write in EnterRegion() may "complete" before the other thread reads the flag.]
For other devices, you might want other fences to enforce the ordering of reads/writes of turn and interested[]. But I don't pretend to know enough to advise on ARM or POWERPC or anything else.
I have a simple program using signal with the user's handlers.
#include <signal.h>
#include <stdio.h>
#include <zconf.h>
int x = 0;
int i = 3;
void catcher3(int signum) {
i = 1;
}
void catcher2(int signum) {
// Stuck in infinity loop here.
// Happens even with i == 0
if (i != 0) {
x = 5;
}
}
void catcher1(int signum) {
printf("i = %d\n", i);
i--;
if (i == 0) {
signal(SIGFPE, catcher2);
signal(SIGTERM, catcher3);
}
}
int main() {
signal(SIGFPE, catcher1);
x = 10 / x;
printf("Goodbye");
}
While I expect it to print:
3
2
1
Goodbye
It actually prints:
3
2
1
# Infinity loop within catcher2
My questions are:
On running a user handler like catcher1, to which point the code returns after the handler's execution? I would expect it continue the execution but it re-runs the signal handler.
What causes the infinity loop?
How to fix it?
Why sending SIGTERM won't print "Goodbye"? (kill -s TERM <pid>)
As pointed out by AProgrammer, the program doesn't necessarily read x after returning from the handler, even if x is marked volatile (which it should be anyway). This is because the execution continues to the offending instruction. The read from memory and the actual division could be separate instructions.
To get around this you will have to continue the execution to a point before x was read from memory.
You can modify your program as follows -
#include <csetjmp>
jmp_buf fpe;
volatile int x = 0; // Notice the volatile
volatile int i = 3;
void catcher2(int signum) {
if (i != 0) {
x = 5;
longjump(fpe, 1);
}
}
int main() {
signal(SIGFPE, catcher1);
setjump(fpe);
x = 10 / x;
printf("Goodbye");
}
Rest of the functions can remain the same.
You should also not be using printf from the signal handler. Instead use write directly to print debug messages as -
write(1, "SIGNAL\n", sizeof("SIGNAL\n"));
The handling of signals is complex and full of implementation defined, unspecified and undefined behavior. If you want to be portable, there is in fact very few things that you can do. Mostly reading and writing volatile sig_atomic_t and calling _Exit. Depending on the signal number, it is often undefined if you leave the signal handler in another way than calling _Exit.
In your case, I think FPE is one of those signals for which leaving normally the signal handler is UB. The best I can see is restarting the machine instruction which triggered the signal. Few architectures, and last I looked x86 was not one of them, provide a way to do 10/x without loading x in a register; that means that restarting the instruction will always restart the signal, even if you modify x and x us a volatile sig_atomtic_t.
Usually longjmp is also able to leave signal handler. #Bodo confirmed that using setjmp and longjmp to restart the division, you can get the behavior you want.
Note: on Unix there is another set of functions, sigaction, siglongjump and others, which is better to use. In fact I don't recommend using something else in any serious program.
I am developing a program in C to run on a raspberry board. In the program i want to use WiringPiISR to handle a pin triggered interrupt. However, I have found that instead of blocking the main routine, the wiringPiISR creates a concurrent thread. Am i missing something?
Minimal code example :
#include <WiringPi.h>
#include <unistd.h>
int Check=0;
void Isr()
{
while (1)
{
sleep(1);
Check++;
}
}
int main()
{
wiringPiSetup () ;
pinMode(7, INPUT) ;
wiringPiISR (7, INT_EDGE_BOTH ,&Isr);
while (1)
{
sleep(2);
printf("check : %d", Check );
}
return 0;
}
I would expect this minimal program to never resume after the interrupt is fired but in my case it kept on incrementing the variable check and printing it on the screen ( both threads working concurrently).
The documentation I've found is rather specific (emphasis mine):
int wiringPiISR (int pin, int edgeType, void (*function)(void)) ;
This function is run at a high priority (if the program is run using sudo, or as root) and executes concurrently with the main program. It has full access to all the global variables, open file handles and so on.
The sources don't leave anything to imagination. It just crates a new thread:
pthread_create (&threadId, NULL, interruptHandler, &pin) ;
that waits for interrupt and executes your handler:
static void *interruptHandler (void *arg)
{
int pin = *(int *)arg ;
(void)piHiPri (55) ;
for (;;)
{
if (waitForInterrupt (pin, -1) > 0)
isrFunctions [pin] () ;
}
return NULL ;
}
So your handler runs as a separate thread and your behavior is expected.
ISR stands for interrupt service routine aka interrupt handler.
Your code sets up an interrupt handler. If the interrupt is fired, the regular code (main() in your case) is interrupted and the interrupt handler is executed. It's not a second thread but the result is similar.
Interrupt handlers should only do minimal work and quickly return control to the interrupted program. The use of sleep() in an interrupt handler is not allowed and causes undefined behavior.
Assuming that you've made the infinite loop and the call of sleep() on purpose:
sleep() probably allows to switch between the threads.
First of all, let me apologize as I can see that similar questions have been posted quite a few times in the past. However, as I am very unfamiliar with C, I need help confirming this.
I am trying to ensure that my program leaves a clean gpio if I interrupt it with CTRL+C. Easily done in python or java, but C proves to be a harder nut to crack for me, as I was led to believe that no try-catch-finally exists in C. Googling it, I found what I think may be the solution, but unexperienced as I am, I'm not sure it's done properly. Here is my code:
#include <stdio.h>
#include <wiringPi.h>
#include <signal.h>
void CleanGPIO() {
pinMode(1,INPUT);
}
int main()
{
wiringPiSetup();
signal(SIGINT, CleanGPIO);
pinMode(1, PWM_OUTPUT);
for (int i = 0; i < 1024; ++i) {
pwmWrite(1, i);
delay(1);
}
for (int i = 1023; i >= 0; --i) {
pwmWrite(1, i);
delay(1);
}
pinMode(1,INPUT);
return 0;
}
I have tested it and it works as intended (pin 1 is set as IN after I interrupt it with CTRL+C), but I'm concerned if this is the safe way to do it, and if there is a better solution available.
calling any function which is not speficied as signal-safe from a signal handler is undefined behaviour. I suppose there is no such guarantee about pinMode.
The proper way would be to set a volatile int flag that you periodically check in your main loop.
volatile int terminating = 0;
void terminate(int sign) {
signal(SIGINT, SIG_DFL);
terminating = 1;
}
int main() {
for (...) {
if (terminating) {
// cleanup
exit(1);
}
}
}
the call to signal inside the handler is to allow force terminating the program with a second ctrl+c in case proper clenup takes too long or is stuck for any reason.
Your solution is nearly right. You should also call exit in order to force the program to terminate (assuming you want to terminate immediately). The exit call takes a parameter which is the exit status to return to the caller (e.g., the shell). This should be non-zero for abnormal termination.
So, it should be:
void CleanGPIO() {
pinMode(1,INPUT);
exit(1);
}
If you don't want to exit from the handler but from main in a more controlled fashion you can set a flag instead and check the flag value inside the loops.