-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ac7e490
commit 5c843d2
Showing
11 changed files
with
428 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
{ | ||
"files.associations": { | ||
"types.h": "c" | ||
} | ||
"types.h": "c", | ||
"stdio.h": "c", | ||
"unistd.h": "c" | ||
}, | ||
"C_Cpp.errorSquiggles": "disabled" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// This example replaces the signal mask and then suspends execution. | ||
#define _POSIX_SOURCE | ||
#include <stdio.h> | ||
#include <signal.h> | ||
#include <time.h> | ||
#include <unistd.h> | ||
|
||
void catcher(int signum) | ||
{ | ||
switch (signum) | ||
{ | ||
case SIGUSR1: | ||
puts("catcher caught SIGUSR1"); | ||
break; | ||
case SIGUSR2: | ||
puts("catcher caught SIGUSR2"); | ||
break; | ||
default: | ||
printf("catcher caught unexpected signal %d\n", signum); // bad idea to call printf in handler | ||
} | ||
} | ||
|
||
int main() | ||
{ | ||
sigset_t sigset; | ||
struct sigaction sact; | ||
time_t t; | ||
|
||
if (fork() == 0) | ||
{ | ||
sleep(10); | ||
puts("child is sending SIGUSR2 signal which should be blocked"); | ||
kill(getppid(), SIGUSR2); | ||
sleep(5); | ||
puts("child is sending SIGUSR1 signal which should be caught"); | ||
kill(getppid(), SIGUSR1); | ||
exit(0); | ||
} | ||
|
||
sigemptyset(&sact.sa_mask); | ||
sact.sa_flags = 0; | ||
sact.sa_handler = catcher; | ||
|
||
if (sigaction(SIGUSR1, &sact, NULL) != 0) | ||
perror("1st sigaction() error"); | ||
|
||
if (sigaction(SIGUSR2, &sact, NULL) != 0) | ||
perror("2nd sigaction() error"); | ||
|
||
sigfillset(&sigset); | ||
sigdelset(&sigset, SIGUSR1); | ||
time(&t); | ||
printf("parent waiting for child to send SIGUSR1 at %s", ctime(&t)); | ||
if (sigsuspend(&sigset) == -1) // blocks all except for SIGUSR1 | ||
perror("sigsuspend () returned -1 as expected"); | ||
|
||
printf("sigsuspend is over at %s", ctime(time(&t))); | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
112 changes: 112 additions & 0 deletions
112
CSE344 - System Programming/Coding Practices/practice21.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
// waiting for signals... | ||
// ! Important ! | ||
/* | ||
Busy waiting is a method of waiting for a signal to occur. | ||
Using busy waiting is easy, however, | ||
CPU usage will be 100%. | ||
When this happens, other processes will not be able to run. | ||
! Do not use busy waiting ! | ||
-- from slides -- | ||
busy waiting: testing continuously (within a loop) whether | ||
a certain event occurred by using CPU cycles. | ||
The alternative is to suspend the process until a signal arrives | ||
notifying it that the event occurred (hence the CPU is free). | ||
POSIX system calls for suspending process until a signal occurs: | ||
- sleep (NO) x | ||
- nanosleep (NO) x | ||
- pause (NO) x | ||
- sigsuspend (YES) v | ||
*/ | ||
|
||
/* | ||
sleep() and nanosleep() (BAD PRACTICE) | ||
Returns 0 on normal completion, or number of unslept seconds if | ||
prematurely terminated. | ||
#include <unistd.h> | ||
--> unsigned int sleep(unsigned int seconds); | ||
nanosleep is a more powerful version of sleep that operates at higher | ||
resolution. | ||
*/ | ||
|
||
/* | ||
pause() (BAD PRACTICE) | ||
Suspends the process until a signal is received. (or an unhandled signal terminates the process) | ||
Always returns -1 and sets errno to EINTR. | ||
#include <unistd.h> | ||
--> int pause(void); | ||
for (;;) // infinite loop | ||
pause(); // wait for a signal | ||
*/ | ||
|
||
// Why pause() is insufficient? | ||
|
||
#include <stdio.h> | ||
#include <signal.h> | ||
#include <unistd.h> | ||
#include <stdlib.h> | ||
|
||
void handler(int sig) | ||
{ | ||
printf("Ouch!\n"); | ||
} | ||
|
||
int main() | ||
{ | ||
sigset_t prevMask, intMask; | ||
struct sigaction sa; // action to be taken when a signal is received | ||
|
||
// add SIGINT to the mask set | ||
sigemptyset(&intMask); | ||
sigaddset(&intMask, SIGINT); | ||
|
||
// Handle SIGINT (action) | ||
sigemptyset(&sa.sa_mask); | ||
sa.sa_flags = 0; | ||
sa.sa_handler = &handler; | ||
|
||
// sig num, action, old action | ||
if (sigaction(SIGINT, &sa, NULL) == -1) | ||
{ | ||
perror("sigaction"); | ||
exit(EXIT_FAILURE); | ||
} | ||
|
||
/* Block SIGINT prior to execut ing critical section. (At this | ||
point we assume that SIGINT is not already blocked.) */ | ||
if (sigprocmask(SIG_BLOCK, &intMask, &prevMask) == -1) | ||
{ | ||
perror("sigprocmask - SIG_BLOCK"); | ||
exit(EXIT_FAILURE); | ||
} | ||
|
||
/* Critical section : do some work here that must not be | ||
interrupted by the SIGINT handler */ | ||
printf("Critical section time starts now...\n"); | ||
sleep(3); | ||
printf("Critical section time ends now...\n"); | ||
|
||
/* End of critical section - restore old mask to unblock SIGINT */ | ||
if (sigprocmask(SIG_SETMASK, &prevMask, NULL) == -1) | ||
{ | ||
perror("sigprocmask - SIG_SETMASK"); | ||
exit(EXIT_FAILURE); | ||
} | ||
|
||
/* BUG: | ||
what if SIGINT arrives now... (BURADA GELIRSE SICTIK) */ | ||
|
||
pause(); // Wait for SIGINT | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// sigsuspend (WAITING FOR SIGNALS) example | ||
|
||
/* | ||
#include <signal.h> | ||
int sigsuspend(const sigset_t *mask); | ||
// returns -1 with errno set to EINTR | ||
!! Main Idea !! | ||
block the process efficiently until a certain signal arrives and is handled. | ||
Atomically unblocks a signal and suspends the process. | ||
[Atomically: the process is blocked from receiving signals until | ||
the process is suspended. -Copilot] | ||
Equivalent to (atomic): | ||
// Assign new mask and get old mask | ||
sigprocmask(SIG_SETMASK, mask, &oldMask); | ||
pause(); | ||
// Restore old mask | ||
sigprocmask(SIG_SETMASK, &oldMask, NULL); | ||
sigsuspend() does these 3 operations atomically. | ||
- block the process from receiving signals | ||
- suspend the process | ||
- restore the old mask automatically after an unmasked signal | ||
is received. | ||
Thanks to sigsuspend(), | ||
- we can avoid busy waiting | ||
- two processes can synchronize themselves where one process | ||
waits for a signal from the other process. | ||
*/ | ||
|
||
// --- Issues Can Be Encountered --- | ||
/* | ||
1- Handling Errors | ||
// take a backup of errno | ||
void my_handler(int sig) | ||
{ | ||
int esaved = errno; // save errno | ||
// do something | ||
errno = esaved; // restore errno | ||
} | ||
*/ | ||
|
||
/* | ||
2- System Calls Interrupted by a Signal | ||
while((cnt = read(fd, buf, BUF_SIZE)) == -1 && errno == EINTR) | ||
continue; // Do nothing loop body | ||
if (cnt == -1) | ||
perror("read") | ||
-- Create a macro to handle this issue -- | ||
#define NO_EINTR(stmt) while ((stmt) == -1 && errno == EINTR); | ||
NO_EINTR(cnt = read(fd, buf, BUF_SIZE)); | ||
if (cnt == -1) | ||
perror("read"); | ||
*/ | ||
|
||
/* | ||
3- Signal Handler Function Risks | ||
- Do not call any function that is not async-signal-safe | ||
from a signal handler function. | ||
(e.g. printf, malloc, free, etc.) | ||
- Do not use global variables in a signal handler function. | ||
What to do? | ||
Try to use as few instructions as possible in a signal handler function. | ||
Do not use C library functions. | ||
* Keep function short | ||
If you need to use a C library function do them in the main program | ||
pseduo code: | ||
signal_handler: | ||
sets a flag variable to indicate that a signal has been received | ||
main: | ||
loop: | ||
do lengthy work | ||
if (flag variable is set) | ||
do something (for example: exit) | ||
end loop | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// How to create a process | ||
|
||
// system() (not a system call) | ||
|
||
/* | ||
#include <stdlib.h> | ||
--> int system(const char *command); | ||
1- runs the shell | ||
2- executes the command | ||
so, it creates 2 processes. | ||
Therefore, it is not efficient. | ||
It is not secure beacuse, | ||
since it uses the shell, | ||
it is as secure as the shell. | ||
*/ | ||
|
||
// !! Unsafe !! | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
|
||
int main() | ||
{ | ||
int return_value; | ||
|
||
return_value = system("ls"); | ||
|
||
return return_value; | ||
} | ||
|
||
// What to use instead | ||
/* | ||
Creating process by system calls has 2 steps: | ||
1- fork() | ||
2- exec() | ||
`fork`: that creates a child process that is an exact copy of its parent process. | ||
`exec`: causees a particular process to cease (terminate) being an instance | ||
of one program to installed become instance of a program | ||
*/ |
Oops, something went wrong.