SCHED_DEADLINE runtime overrun signal (SIGXCPU) - c

I'm implementing a rt-thread using SCHED_DEADLINE. I'm trying to catch a SIGXCPU-signal,
if the thread exceeds the specified sched_runtime. To my understanding of the manpage, this can be achived by setting the SCHED_FLAG_DL_OVERRUN-flag. However, in the example program below, no signal is received (on the third iteration). According to the kernelshark-plot, the thread is suspended after it reaches its runtime but no signal is created.
Is my understanding of the SCHED_FLAG_DL_OVERRUN-flag correct? If not, is there another way to detect, if a thread exceeds the specified runtime, without measuring the time after each iteration?
My kernel version is 5.4.3-rt1-1-rt #1 SMP PREEMPT_RT.
#include <unistd.h>
#include <linux/unistd.h>
#include <linux/types.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/sched.h>
#define gettid() syscall(__NR_gettid)
#define SCHED_DEADLINE 6
/* XXX use the proper syscall numbers */
#ifdef __x86_64__
#define __NR_sched_setattr 314
#define __NR_sched_getattr 315
#endif
#ifdef __i386__
#define __NR_sched_setattr 351
#define __NR_sched_getattr 352
#endif
#ifdef __arm__
#define __NR_sched_setattr 380
#define __NR_sched_getattr 381
#endif
static volatile int done;
struct sched_attr {
__u32 size;
__u32 sched_policy;
__u64 sched_flags;
/* SCHED_NORMAL, SCHED_BATCH */
__s32 sched_nice;
/* SCHED_FIFO, SCHED_RR */
__u32 sched_priority;
/* SCHED_DEADLINE (nsec) */
__u64 sched_runtime;
__u64 sched_deadline;
__u64 sched_period;
};
int sched_setattr(pid_t pid,
const struct sched_attr *attr,
unsigned int flags)
{
return syscall(__NR_sched_setattr, pid, attr, flags);
}
int sched_getattr(pid_t pid,
struct sched_attr *attr,
unsigned int size,
unsigned int flags)
{
return syscall(__NR_sched_getattr, pid, attr, size, flags);
}
void set_rt(int pid, unsigned long runtime, unsigned long period, unsigned long deadline){
struct sched_attr attr;
unsigned int flags = 0;
attr.size = sizeof(attr);
attr.sched_flags = SCHED_FLAG_DL_OVERRUN;
attr.sched_nice = 0;
attr.sched_priority = 0;
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = runtime;
attr.sched_period = period;
attr.sched_deadline = deadline;
int ret = sched_setattr(pid, &attr, 0);
if (ret < 0) {
done = 0;
perror("sched_setattr");
exit(-1);
}
struct sched_attr param;
ret = sched_getattr(pid, &param, sizeof(param), 0);
if (ret < 0) {
done = 0;
perror("sched_getattr");
exit(-1);
}
}
void sig_handler(int signo)
{
if (signo == SIGXCPU)
printf("received SIGXCPU\n");
}
int main (void) {
printf("MY PID: %d\n", getpid());
set_rt(gettid(), 500000000Ul, 1000000000Ul, 1000000000Ul);
struct sigaction s;
bzero(&s, sizeof(s));
s.sa_handler = sig_handler;
sigaction (SIGXCPU, &s, NULL);
//test signal handler
kill(getpid(), SIGXCPU);
int i = 0;
while (1) {
i++;
printf("Loop Number %d\n", i);
int k = 900000000;
if (i == 3) {
while (k > 0) k--;
}
sched_yield();
}
}

Related

Why is printf blocked by while(trylock) on CentOS 7?

Start two threads with policy SCHED_RR and priority 45.
One thread's affinity is 0x0004, and another is 0x0008.(my computer contains four cpu cores. system is CentOS 7, not a virtual machine.)
The subTask is simple:
spinning trylock in the while.
call printf show the information.
free the lock.
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <sched.h>
#include <pthread.h>
#define CHECK_ERROR(call)\
do{\
int _error = (call);\
if(_error != 0){\
printf("*** Error *** at [%s:%d] error=%d \n", __FILE__, __LINE__, _error);\
}\
}while(0)
int getThreadCores(pthread_t thread, int *cores);
int getThreadPP(pthread_t thread, int *policy, int *priority);
int setThreadAttrCores(pthread_attr_t *attr, int cores);
int setThreadAttrPP(pthread_attr_t *attr, int policy, int priority);
#define SUB_THREAD_NUM (2)
static int threadsId[SUB_THREAD_NUM];
static pthread_t subThreads[SUB_THREAD_NUM];
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void *subTask(void *data)
{
int id = *(int*)data;
int policy=0, priority=0, cores=0;
CHECK_ERROR(getThreadCores(pthread_self(), &cores));
CHECK_ERROR(getThreadPP(pthread_self(), &policy, &priority));
printf("the sub thread %d, cores 0x%x, policy %d, priority %d\n",
id,cores,policy,priority);
int n = 1024*10;
int i;
for(i=0;i<n;++i)
{
while(pthread_mutex_trylock(&lock)){}
printf("the sub thread %d, out put %d\n",id,i);
CHECK_ERROR(pthread_mutex_unlock(&lock));
}
return NULL;
}
int main(int argc, char *argv[])
{
pthread_attr_t attr;
CHECK_ERROR(pthread_attr_init(&attr));
int i;
for(i=0;i<SUB_THREAD_NUM;++i)
{
threadsId[i] = i;
CHECK_ERROR(setThreadAttrCores(&attr, 0x0004<<i));
CHECK_ERROR(setThreadAttrPP(&attr, SCHED_RR, 1));
CHECK_ERROR(pthread_create(&subThreads[i],&attr,subTask,threadsId+i));
}
CHECK_ERROR(pthread_attr_destroy(&attr));
for(i=0;i<SUB_THREAD_NUM;++i)
{
CHECK_ERROR(pthread_join(subThreads[i],NULL));
}
printf("multiThreadTest success\n");
return 0;
}
int getThreadCores(pthread_t thread, int *cores)
{
int error = 0;
int cpuNum = sysconf(_SC_NPROCESSORS_CONF);
int _cores = 0;
cpu_set_t mask;
CPU_ZERO(&mask);
error = pthread_getaffinity_np(thread, sizeof(cpu_set_t), &mask);
if(error == 0)
{
int i;
for(i=0;i<cpuNum;++i)
{
if(CPU_ISSET(i, &mask))
{
_cores |= (0x1 << i);
}
}
}
*cores = _cores;
return error;
}
int getThreadPP(pthread_t thread, int *policy, int *priority)
{
int error = 0;
struct sched_param sp;
error = pthread_getschedparam(thread,policy,&sp);
*priority = sp.sched_priority;
return error;
}
static void setCpuSetMask(cpu_set_t *mask, int cores)
{
int cpuNum = sysconf(_SC_NPROCESSORS_CONF);
CPU_ZERO(mask);
int i;
for(i=0;i<cpuNum;++i)
{
if(((cores>>i)&0x1) == 1)
{
CPU_SET(i, mask);
}
}
}
int setThreadAttrCores(pthread_attr_t *attr, int cores)
{
cpu_set_t mask;
if(cores<0)cores=0xFFFFFFFF;
setCpuSetMask(&mask,cores);
return pthread_attr_setaffinity_np(attr, sizeof(cpu_set_t), &mask);
}
int setThreadAttrPriority(pthread_attr_t *attr, int priority)
{
struct sched_param sp;
sp.sched_priority = priority;
return pthread_attr_setschedparam(attr,&sp);
}
int setThreadAttrPP(pthread_attr_t *attr, int policy, int priority)
{
int error = 0;
//firstly, set the inherit to PTHREAD_EXPLICIT_SCHED
error |= pthread_attr_setinheritsched(attr,PTHREAD_EXPLICIT_SCHED);
error |= pthread_attr_setschedpolicy(attr,policy);
error |= setThreadAttrPriority(attr,priority);
return error;
}
compile: gcc -Wall -O3 -lpthread multiThreadTest.c -o multiThreadTest
My question is: the program blocked, one thread blocked in printf and another blocked in spinning trylock, why?
If I change the policy to SCHED_OTHER and the priority to 0, the program unblocked.
If I change the while(pthread_mutex_trylock(&lock)){} to CHECK_ERROR(pthread_mutex_lock(&lock)); the program unblocked.
If I change the while(pthread_mutex_trylock(&lock)){} to while(pthread_mutex_trylock(&lock)){usleep(1);} the program unblocked.
And if I change the printf to fprintf, the program unblocked.
And if I run the same program on Ubuntu system, it is unblocked.

Implementing bcc's killsnoop in C

I'm trying to implement the killsnoop.py program in bcc in C. When executing the program, I'm getting a failed to load: -13 error. Can someone help me to debug this?
Note: For compilation, I've taken the libbpf-bootstrap example from Andrii Nakryiko's blog post.
Error message:
Below is the program that I've used.
killsnoop.bpf.c
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#include "killsnoop.h"
struct val_t {
__u32 uid;
__u32 pid;
int sig;
int tpid;
char comm[TASK_COMM_LEN];
};
struct data_t {
__u32 uid;
__u32 pid;
int tpid;
int sig;
int ret;
char comm[TASK_COMM_LEN];
};
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, __u32);
__type(value, struct val_t);
__uint(max_entries, 10240);
} info_map SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, __u32);
__type(value, struct data_t);
__uint(max_entries, 10240);
} event SEC(".maps");
SEC("kprobe/__x64_sys_kill")
int entry_probe(struct pt_regs *ctx, int tpid, int sig) {
__u64 pid_tgid = bpf_get_current_pid_tgid();
__u32 pid = pid_tgid >> 32;
__u32 tid = (__u32) pid_tgid;
__u64 uid_gid = bpf_get_current_uid_gid();
__u32 uid = (__u32) uid_gid;
struct val_t val = {
.uid = uid,
.pid = pid
};
if (bpf_get_current_comm(&val.comm, sizeof(val.comm)) == 0) {
val.tpid = tpid;
val.sig = sig;
bpf_map_update_elem(&info_map, &tid, &val, BPF_ANY);
}
return 0;
}
SEC("kretprobe/__x64_sys_kill")
int return_probe(struct pt_regs *ctx) {
struct data_t data = {};
struct val_t *valp;
__u64 pid_tgid = bpf_get_current_pid_tgid();
__u32 pid = pid_tgid >> 32;
__u32 tid = (__u32) pid_tgid;
valp = bpf_map_lookup_elem(&info_map, &tid);
if (!valp) {
return 0; // missed entry
}
bpf_core_read(&data.comm, sizeof(data.comm), valp->comm);
data.pid = pid;
data.tpid = valp->tpid;
data.ret = PT_REGS_RC_CORE(ctx);
data.sig = valp->sig;
data.uid = valp->uid;
bpf_perf_event_output(ctx, &event, BPF_F_CURRENT_CPU, &data, sizeof(data));
bpf_map_delete_elem(&info_map, &tid);
return 0;
}
killsnoop.c
#include <signal.h>
#include "killsnoop.skel.h"
#include "killsnoop.h"
#define OUTPUT_FORMAT "%lld %d %d %s %d %d"
#define PERF_POLL_TIMEOUT_MS 10
#define PERF_BUFFER_PAGES 64
static volatile int shutdown = 0;
static void sig_int(int signal) {
shutdown = 1;
}
void handle_event(void *ctx, int cpu, void *data, u32 data_size) {
const struct event *e = data;
time_t curr_time;
time(&curr_time);
printf(OUTPUT_FORMAT, (long long) curr_time, e->pid, e->tpid, e->comm, e->sig, e->uid);
}
void handle_lost_event(void *ctx, int cpu, u64 lost_cnt) {
fprintf(stderr, "Lost %llu events on CPU #%d!\n", lost_cnt, cpu);
}
int main(int argc, char **argv) {
int err;
struct perf_buffer *perfBuffer;
struct killsnoop_bpf *obj;
obj = killsnoop_bpf__open_and_load();
if (!obj) {
fprintf(stderr, "failed to open/load BPF skeleton!");
goto cleanup;
}
err = killsnoop_bpf__attach(obj);
if (err) {
fprintf(stderr, "failed to attach BPF programs\n");
goto cleanup;
}
perfBuffer = perf_buffer__new(bpf_map__fd(obj->maps.info_map), PERF_BUFFER_PAGES, handle_event, handle_lost_event,
NULL, NULL);
if (!perfBuffer) {
err = -errno;
fprintf(stderr, "failed to open perf buffer: %d\n", err);
goto cleanup;
}
if (signal(SIGINT, sig_int) == SIG_ERR) {
fprintf(stderr, "can't set signal handler: %s\n", strerror(errno));
err = 1;
goto cleanup;
}
while (!shutdown) {
err = perf_buffer__poll(perfBuffer, PERF_POLL_TIMEOUT_MS);
if (err < 0 && err != -EINTR) {
fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err));
goto cleanup;
}
/* reset err to return 0 if exiting */
err = 0;
}
cleanup:
perf_buffer__free(perfBuffer);
killsnoop_bpf__destroy(obj);
return err != 0;
}
killsnoop.h
#define TASK_COMM_LEN 16
typedef unsigned int u32;
typedef unsigned long long u64;
struct event {
u32 uid;
u32 pid;
int tpid;
int sig;
int ret;
char comm[TASK_COMM_LEN];
};
BCC tends to do a little bit of background magic which allows you to use the arguments of the attachment point directly in your eBPF program like you are doing:
entry_probe(struct pt_regs *ctx, int tpid, int sig)
However, this is BCC specific. With libbpf you have to use the BPF_KPROBE_SYSCALL macro to get similar behavior. For example: https://elixir.bootlin.com/linux/v5.18.14/source/tools/testing/selftests/bpf/progs/bpf_syscall_macro.c#L68
In your case:
SEC("kprobe/" SYS_PREFIX "sys_kill")
int BPF_KPROBE_SYSCALL(entry_probe, int tpid, int sig) {
...
The reason you are getting this error is because all arguments are saves to the stack once the BPF program is entered. Thus the program attempts to write R3 which is int sig in this case to the stack. But R3 is not defined, only R1 is which is the ctx. And you are not allowed to read from uninitialized registers hence the R3 !read_ok error.

C, timer_settime, disarm timer and overwrite associated data?

I have to do for University a project about UDP, where i have to guarantee reliable communication; for packets, i want use timer_gettime() and timer_Settime() functions, because i can queue signals and i can associate to them a timer; in particular, struct sigevent has a field which union sigval where i can pass value to handler when signal arrived; I would like to take advantage of this passing to handler number of packets for which timer expired; I have a problem, and I've done a simple program to verify this; when I start timer, i can disarm it setting it_value of struct sigevent to 0; but data doesn't change; if I send 100 signal, header receives only data of first signal. This is my code:
#include <signal.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
int d;
void err_exit(char* str)
{
perror(str);
exit(EXIT_FAILURE);
}
void sighandler(int sig, siginfo_t *si, void *uc)
{
(void) sig;
(void) uc;
d = si->si_value.sival_int;
}
void handle_signal(struct sigaction* sa)
{
sa->sa_flags = SA_SIGINFO;
sa->sa_sigaction = sighandler;
sigemptyset(&sa->sa_mask);
if (sigaction(SIGRTMAX,sa,NULL) == -1)
err_exit("sigaction");
}
void create_timer(struct sigevent* sev,timer_t* timer_id,int i)
{
union sigval s;
s.sival_int = i;
printf("value: %d\n",i);
sev->sigev_notify = SIGEV_SIGNAL;
sev->sigev_signo = SIGRTMAX;
sev->sigev_value = s;
timer_create(CLOCK_REALTIME,sev,timer_id);
}
void set_timer(timer_t timer_id,struct itimerspec* ts)
{
if(ts == NULL)
printf("itimerspec null\n");
if (timer_settime(timer_id, 0, ts, NULL) == -1){
printf("errno code: %d\n",errno);
err_exit("timer_settime");
}
}
void initialize_timerspec(struct itimerspec* ts)
{
ts->it_value.tv_sec = 2;
ts->it_value.tv_nsec = 5;
ts->it_interval.tv_sec = 0;
ts->it_interval.tv_nsec = 0;
}
void reset_timer(timer_t timer_id, struct itimerspec* ts)
{
ts->it_value.tv_sec = 0;
ts->it_value.tv_nsec = 0;
ts->it_interval.tv_sec = 0;
ts->it_interval.tv_nsec = 0;
if (timer_settime(timer_id, 0, ts, NULL) == -1){
printf("errno code: %d\n",errno);
err_exit("timer_settime");
}
}
int main()
{
struct sigaction sa;
struct itimerspec ts[2];
struct sigevent sev[2];
timer_t timer_id[2];
handle_signal(&sa);
create_timer(sev,timer_id,0);
initialize_timerspec(ts);
set_timer(timer_id,ts);
reset_timer(timer_id,ts);
create_timer(sev + 1,timer_id + 1,1);
initialize_timerspec(ts + 1);
set_timer(timer_id,ts + 1);
printf("id1: %ju id2: %ju\n",timer_id[0],timer_id[1]);
sleep(10);
printf("d = %d\n",d);
exit(EXIT_SUCCESS);
}
I disarm first timer, and send another signal; but handler receives data associated to first signal, because it prints 0. Is there a way to send to overwrite data, sending to handler data of second signal(in this case 1)?

How to create a file Lock with timeout under linux

I'm trying to lock some critical resources that are accessed by multiple applications under linux.
All the applications will call the acquireLock function on the same file when entering the critical section, and the releaseLock when leaving.
If the lock is not acquired for more than timeot the caller will go ahead doing something else.
The code below works whit slow processes, but under stress the lock is easily broken the lock is acquired by multiple processes, so I guess I'm stumbling in a race condition somewhere.
Can somebody point me out why it's not working and what would be the correct implementation?
Thanks a lot!
MV
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/file.h>
//************************************************************
#define CYCLETIME 1000
//************************************************************
//************************************************************
int acquireLock(char *lockFile, int msTimeout)
{
int lockFd;
int cntTimeout = 0;
if ((lockFd = open(lockFile, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO)) < 0)
return -1;
while (flock(lockFd, LOCK_EX | LOCK_NB) < 0){
usleep(CYCLETIME);
cntTimeout++;
if(cntTimeout >= msTimeout){
return -1;
}
}
return lockFd;
}
//*************************************************************
void releaseLock (int lockFd)
{
flock(lockFd, LOCK_UN);
close(lockFd);
}
//************************************************************
It appears that the mistake was in another part of the code, the lock is working as expected.
I share the code I'm using in case it can be helpful to somebody else.
Those are the locking functions:
/* ----------------------------------------------------------------------- *
* Code derived by the flock.c in the "util-linux" ubuntu package
* by Peter Anvin
* ----------------------------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/file.h>
#include <sys/time.h>
#include <signal.h>
//************************************************************
static sig_atomic_t timeout_expired = 0;
//************************************************************
static void timeout_handler(int sig)
{
(void)sig;
timeout_expired = 1;
}
//************************************************************
int acquireLock(char *lockFile, int msTimeout)
{
struct itimerval timeout, old_timer;
struct sigaction sa, old_sa;
int err;
int sTimeout = msTimeout/1000;
memset(&timeout, 0, sizeof timeout);
timeout.it_value.tv_sec = sTimeout;
timeout.it_value.tv_usec = ((msTimeout-(sTimeout*1000))*1000);
memset(&sa, 0, sizeof sa);
sa.sa_handler = timeout_handler;
sa.sa_flags = SA_RESETHAND;
sigaction(SIGALRM, &sa, &old_sa);
setitimer(ITIMER_REAL, &timeout, &old_timer);
int lockFd;
int cntTimeout = 0;
if ((lockFd = open(lockFile, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO)) < 0)
return -1;
while (flock(lockFd, LOCK_EX))
{
switch( (err = errno) ) {
case EINTR: /* Signal received */
if ( timeout_expired )
setitimer(ITIMER_REAL, &old_timer, NULL); /* Cancel itimer */
sigaction(SIGALRM, &old_sa, NULL); /* Cancel signal handler */
return -1; /* -w option set and failed to lock */
continue; /* otherwise try again */
default: /* Other errors */
return -1;
}
}
setitimer(ITIMER_REAL, &old_timer, NULL); /* Cancel itimer */
sigaction(SIGALRM, &old_sa, NULL); /* Cancel signal handler */
return lockFd;
}
//***************************************************************
void releaseLock (int lockFd)
{
flock(lockFd, LOCK_UN);
close(lockFd);
}
//************************************************************
... and those can be tried by reading and writing a FIFO
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include "lock.h"
#define LOCKED 1
void main(int argc, char **argv)
{
const char *filename;
const char *fifo_name;
const char *message;
int lockfd, fifoHandle;
filename = argv[1];
fifo_name = argv[2];
message = argv[3];
char bufin[1024];
char bufout[1024];
struct stat st;
int bufsize = strlen(message)+1;
int sleeptime = 0;
int j = 0;
if (stat(fifo_name, &st) != 0)
mkfifo(fifo_name, 0666);
while (1){
if (LOCKED)
lockfd=acquireLock(filename, 15000);
if (lockfd==-1)
printf("timeout expired \n");
fifoHandle= open(fifo_name, O_RDWR);
strcpy(bufin, message);
bufin[bufsize-1] = 0x0;
write(fifoHandle, bufin, sizeof(char)*bufsize);
sleeptime = rand() % 100000;
usleep(sleeptime);
read(fifoHandle, &bufout, sizeof(char)*(bufsize+1));
printf("%s - %d \n", bufout, j);
j= j+1;
if (LOCKED)
releaseLock(lockfd);
sleeptime = rand() % 10000;
}
unlink(fifo_name);
return;
}
by sending in two terminals
./locktestFIFO ./lck ./fifo messageA
./locktestFIFO ./lck ./fifo messageB
if LOCKED is not set to 1 the messages will mix up, otherwise the two threads will take and release the resource correctly.

Assignment from incompatible pointer type — how to fix?

Trying to implement signal handlers but receiving the warning:
assignment from incompatible pointer type [enabled by default]
act.sa_sigaction = sigChldHandler;
... Also my professor pointed out.
char * argv[3];
argv[0]= GUESSER_PROGNAME;
argv[2]= NULL;
this allocates memory for 3 char pointer vars, but they do NOT point anywhere in particular." But I am not sure what he means by that.
\file 1
#include "assign2Headers.h"
pid_t answererPid;
pid_t guesserPid;
int shouldRun = 1;
void sigAlrmHandler(int sig)
{
kill(answererPid,TIME_OVER_SIGNAL);
kill(guesserPid,TIME_OVER_SIGNAL);
shouldRun=0;
}
void sigChldHandler(int sig)
{
wait(NULL);
shouldRun=0;
}
int main(void){
struct sigaction act;
memset(&act, '\0', sizeof(struct sigaction));
act.sa_handler = sigAlrmHandler;
sigaction(SIGALRM, &act, NULL);
act.sa_sigaction = sighldHandler;
sigaction(SIGCHLD, &act, NULL);
char line[LINE_LEN];
char * argv[3];
argv[0]= GUESSER_PROGNAME;
argv[2]= NULL;
answererPid = fork();
if(answererPid == 0){
execl(ANSWERER_PROGNAME,ANSWERER_PROGNAME,(char*)NULL);
}
else{
sleep(1);
snprintf(line,LINE_LEN,"%d",answererPid);
guesserPid=fork();
if(guesserPid==0)
{
execl(GUESSER_PROGNAME,GUESSER_PROGNAME,argv[0],line,(char*)NULL);
}
else
{ alarm(NUM_SECONDS);
while(shouldRun)
sleep(1);
sleep(1);
sleep(1);
printf("launcher finished\n");
return (EXIT_SUCCESS);
}
}
}
\file 2
#include "assign2Headers.h"
int shouldRun = 1;
void timeoverhandler(int sig)
{ sleep(1);
printf("\nOh no! The time is up!\n");
printf("guesser finished\n");
shouldRun=0;
exit(EXIT_SUCCESS);
}
void winsignalhandler(int sig)
{
printf("\nCongratulations! You found it!\n");
shouldRun=0;
signal(WIN_SIGNAL,winsignalhandler);
}
void correctsignalhandler(int sig)
{
printf("Yay! That was right!\n");
signal(CORRECT_SIGNAL,correctsignalhandler);
}
void incorrectsignalhandler(int sig)
{
printf("Oops! That was wrong. Please restart from the beginning.\n"
"\nRe-starting from the beginning:\n");
signal(INCORRECT_SIGNAL,incorrectsignalhandler);
}
int main(int argc,char* argv[])
{
pid_t answererPid=atoi(argv[1]);
signal(TIME_OVER_SIGNAL,timeoverhandler);
signal(WIN_SIGNAL,winsignalhandler);
signal(CORRECT_SIGNAL,correctsignalhandler);
signal(INCORRECT_SIGNAL,incorrectsignalhandler);
while(shouldRun)
{ int guess;
printf("What would you like your next guess to be: 0 or 1? ");
scanf("%d",&guess);
if(guess==0)
kill(answererPid,ZERO_SIGNAL);
if(guess==1)
kill(answererPid,ONE_SIGNAL);
sleep(2);
}
printf("guesser finished\n");
return (EXIT_SUCCESS);
}
\file 3
//--- Common standard header files ---//
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
////--- Common constants: ---//
#define ZERO_SIGNAL SIGUSR1
#define ONE_SIGNAL SIGUSR2
#define CORRECT_SIGNAL SIGUSR1
#define INCORRECT_SIGNAL SIGUSR2
#define WIN_SIGNAL SIGINT
#define TIME_OVER_SIGNAL SIGTERM
#define GUESSER_PROGNAME "guesser"
#define ANSWERER_PROGNAME "answerer"
#define LINE_LEN 256
#define NUM_SECONDS 30
\file 4
//--- Inclusion of header files ---//
#include "assign2Headers.h"
//--- Definition of constants: ---//
#define PATTERN_LEN 4
//--- Definition of global vars: ---//
int answer;
int numCorrect = 0;
int shouldRun = 1;
//--- Definition of global fncs: ---//
void timeUpHandler (int sig
)
{
shouldRun = 0;
}
void guessHandler (int sig,
siginfo_t* infoPtr,
void* dataPtr
)
{
int toSendBack;
int userBit = (sig == ONE_SIGNAL);
int correctBit = ((answer >> numCorrect) & 0x1);
int isCorrect = (correctBit == userBit);
printf("position %d: userBit %d, correctBit %d\n",
numCorrect,userBit,correctBit
);
if (isCorrect)
{
numCorrect++;
if (numCorrect >= PATTERN_LEN)
toSendBack = WIN_SIGNAL;
else
toSendBack = CORRECT_SIGNAL;
}
else
{
numCorrect = 0;
toSendBack = INCORRECT_SIGNAL;
}
kill(infoPtr->si_pid,toSendBack);
}
int main (int argc,
char* argv[]
)
{
// I. Application validity check:
// II. Run program:
// II.A. Initialize random number generator and choice:
srand(getpid());
answer = rand() % (1 << PATTERN_LEN);
printf("(The answer is %d)\n",answer);
// II.B. Install signal handlers:
struct sigaction act;
memset(&act,'\0',sizeof(act));
act.sa_handler = timeUpHandler;
sigaction(TIME_OVER_SIGNAL,&act,NULL);
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = guessHandler;
sigaction(ZERO_SIGNAL,&act,NULL);
sigaction(ONE_SIGNAL,&act,NULL);
// II.C. Hand out while game still active:
while ( (numCorrect < PATTERN_LEN) && shouldRun )
sleep(1);
// III. Finished, return answer:
printf("answerer finished\n");
return(EXIT_SUCCESS);
}
how do I remove this warning and what does he mean by that? Someone help me please.
I guess you are working on Linux. From sigaction manpage :
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
The prototype void sigChldHandler(int sig) does not match with sa_sigaction. Hence the warning.
You can use
sa_handler to set the signal handler function or to specify SIG_IGN/SIG_DFL actions.
sa_sigaction to set the signal handler function - if user needs to access more details like user context and siginfo structure (sender process details, signal type etc). Need to set SA_SIGINFO in the sa_flags for this usage.
For your case, setting sa_handler might be sufficient.
In main():
struct sigaction act;
act.sa_handler = sigChldHandler;
act.sa_flags = SA_RESTART;
sigaction(SIGCHLD, &act, NULL);
Also,
Use separate sigaction structures per signal that you want to set unless you want same handler for them.
Do not mix sigaction() & signal() usages. Stick to one. Maybe, sigaction as it's new & provides more features than signal().
This segment:
char * argv[3];
argv[0]= GUESSER_PROGNAME;
argv[2]= NULL;
Is invalid for argv[0]. Since argv is an array of pointers, you need to make sure those pointers are pointing somewhere before you use them.
This can be achieved with strdup():
argv[0]= strdup(GUESSER_PROGNAME);
Or with malloc()/strcpy():
argv[0]= malloc(strlen(GUESSER_PROGNAME)+1);
strcpy(argv[0], GUESSER_PROGNAME);
Note: malloc() should also be checked, it can return NULL on failure. Any memory allocated on the heap should also be free()'d at the end.
In terms of clarity, you could replace:
#define GUESSER_PROGNAME "guesser"
with:
const char *guesser_progname = "guesser";

Resources