Compléments
Signaux
Numéro | Nom | Description |
---|---|---|
1 | SIGHUP | Instruction (HANG UP) - Fin de session |
2 | SIGINT | Interruption |
3 | SIGQUIT | Instruction (QUIT) |
4 | SIGILL | Instruction illégale |
5 | SIGTRAP | Trace trap |
6 | SIGABRT | (ANSI) Instruction (ABORT) |
6 | SIGIOT | (BSD) IOT Trap |
7 | SIGBUS | Bus error |
8 | SIGFPE | Floating-point exception - Exception arithmétique |
9 | SIGKILL | Instruction (KILL) - termine le processus immédiatement |
10 | SIGUSR1 | Signal utilisateur 1 |
11 | SIGSEGV | Violation de mémoire |
12 | SIGUSR2 | Signal utilisateur 2 |
13 | SIGPIPE | Broken PIPE - Erreur PIPE sans lecteur |
14 | SIGALRM | Alarme horloge |
15 | SIGTERM | Signal de terminaison |
16 | SIGSTKFLT | Stack Fault |
17 | SIGCHLD ou SIGCLD | modification du statut d’un processus fils |
18 | SIGCONT | Demande de reprise du processus |
19 | SIGSTOP | Demande de suspension imbloquable |
20 | SIGTSTP | Demande de suspension depuis le clavier |
21 | SIGTTIN | lecture terminal en arrière-plan |
22 | SIGTTOU | écriture terminal en arrière-plan |
23 | SIGURG | évènement urgent sur socket |
24 | SIGXCPU | temps maximum CPU écoulé |
25 | SIGXFSZ | taille maximale de fichier atteinte |
26 | SIGVTALRM | alarme horloge virtuelle |
27 | SIGPROF | Profiling alarm clock |
28 | SIGWINCH | changement de taille de fenêtre |
29 | SIGPOLL | (System V) occurence d’un évènement attendu |
29 | SIGIO | (BSD) I/O possible actuellement |
30 | SIGPWR | Power failure restart |
31 | SIGSYS | Erreur d’appel système |
Daemon (sans fork
)
main.c
/**
* Copyright 2015 University of Applied Sciences Western Switzerland / Fribourg
*
* SPDX-License-Identifier: Apache-2.0
*
* Project: HEIA-FR / Embedded Systems Laboratory
*
* Abstract: Process and daemon samples
*
* Purpose: This module implements a simple application to be launched from
* /etc/inttab.
* --> this application requires /opt/daemon as root directory
*
* Autĥor: Daniel Gachet
* Date: 17.11.2015
*/
#define _XOPEN_SOURCE 600
#define _DEFAULT_SOURCE
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <syslog.h>
#include <unistd.h>
#define UNUSED(x) (void)(x)
static int signal_catched = 0;
static void catch_signal(int signal)
{
syslog(LOG_INFO, "signal=%d catched\n", signal);
signal_catched++;
}
int main(int argc, char* argv[])
{
UNUSED(argc);
UNUSED(argv);
// daemon's steps 1 to 3 skipped
// 4. capture all required signals
struct sigaction act = {
.sa_handler = catch_signal,
};
sigaction(SIGHUP, &act, NULL); // 1 - hangup
sigaction(SIGINT, &act, NULL); // 2 - terminal interrupt
sigaction(SIGQUIT, &act, NULL); // 3 - terminal quit
sigaction(SIGABRT, &act, NULL); // 6 - abort
sigaction(SIGTERM, &act, NULL); // 15 - termination
sigaction(SIGTSTP, &act, NULL); // 19 - terminal stop signal
// 5. update file mode creation mask
umask(0027);
// 6. change working directory to appropriate place
if (chdir("/opt") == -1) {
syslog(LOG_ERR, "ERROR while changing to working directory");
exit(1);
}
// 7. close all open file descriptors
for (int fd = sysconf(_SC_OPEN_MAX); fd >= 0; fd--) {
close(fd);
}
// 8. redirect stdin, stdout and stderr to /dev/null
if (open("/dev/null", O_RDWR) != STDIN_FILENO) {
syslog(LOG_ERR, "ERROR while opening '/dev/null' for stdin");
exit(1);
}
if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO) {
syslog(LOG_ERR, "ERROR while opening '/dev/null' for stdout");
exit(1);
}
if (dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) {
syslog(LOG_ERR, "ERROR while opening '/dev/null' for stderr");
exit(1);
}
// 9. option: open syslog for message logging
openlog(NULL, LOG_NDELAY | LOG_PID, LOG_DAEMON);
syslog(LOG_INFO, "Daemon has started...");
// 10. option: get effective user and group id for appropriate's one
struct passwd* pwd = getpwnam("daemon");
if (pwd == 0) {
syslog(LOG_ERR, "ERROR while reading daemon password file entry");
exit(1);
}
// 11. option: change root directory
if (chroot(".") == -1) {
syslog(LOG_ERR, "ERROR while changing to new root directory");
exit(1);
}
// 12. option: change effective user and group id for appropriate's one
if (setegid(pwd->pw_gid) == -1) {
syslog(LOG_ERR, "ERROR while setting new effective group id");
exit(1);
}
if (seteuid(pwd->pw_uid) == -1) {
syslog(LOG_ERR, "ERROR while setting new effective user id");
exit(1);
}
// 13. implement daemon body...
int t = 30;
do {
t = sleep(t);
} while (t > 0);
syslog(LOG_INFO,
"daemon stopped. Number of signals catched=%d\n",
signal_catched);
closelog();
return 0;
}
Makefile
EXE=appl
SRCS=$(wildcard *.c)
CFLAGS=-Wall -Wextra -g -c -O0 -MD -std=gnu11
TOOLCHAIN_PATH=/buildroot/output/host/usr/bin/
TOOLCHAIN=$(TOOLCHAIN_PATH)aarch64-linux-
CFLAGS+=-mcpu=cortex-a53 -funwind-tables
##CFLAGS+=-O2 -fno-omit-frame-pointer
OBJDIR=.obj/nano
EXEC=$(EXE)
CC=$(TOOLCHAIN)gcc
LD=$(TOOLCHAIN)gcc
AR=$(TOOLCHAIN)ar
STRIP=$(TOOLCHAIN)strip
OBJDIR=.obj/$(target)
OBJS= $(addprefix $(OBJDIR)/, $(SRCS:.c=.o))
$(OBJDIR)/%o: %c
$(CC) $(CFLAGS) $< -o $@
all: $(OBJDIR)/ $(EXEC)
echo $(EXEC)
echo $(SRCS)
$(EXEC): $(OBJS) $(LINKER_SCRIPT)
$(LD) $(OBJS) $(LDFLAGS) -o $@
$(OBJDIR)/:
mkdir -p $(OBJDIR)
clean:
rm -Rf $(OBJDIR) $(EXEC) $(EXEC)_s *~
clean_all: clean
rm -Rf .obj $(EXE) $(EXE)_s $(EXE)_a $(EXE)_a_s $(EXE)_h $(EXE)_h_s
-include $(OBJS:.o=.d)
.PHONY: all clean clean_all
Daemon (complet, avec fork
)
daemon.c
/**
* Copyright 2015 University of Applied Sciences Western Switzerland / Fribourg
*
* SPDX-License-Identifier: Apache-2.0
*
* Project: HEIA-FR / Embedded Systems Laboratory
*
* Abstract: Process and daemon samples
*
* Purpose: This module implements a simple daemon to be launched
* from a /etc/init.d/S??_* script
* -> this application requires /opt/daemon as root directory
*
* Autĥor: Daniel Gachet
* Date: 17.11.2015
*/
#define _XOPEN_SOURCE 600
#define _DEFAULT_SOURCE
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <syslog.h>
#include <unistd.h>
#define UNUSED(x) (void)(x)
static int signal_catched = 0;
static void catch_signal(int signal)
{
syslog(LOG_INFO, "signal=%d catched\n", signal);
signal_catched++;
}
static void fork_process()
{
pid_t pid = fork();
switch (pid) {
case 0:
break; // child process has been created
case -1:
syslog(LOG_ERR, "ERROR while forking");
exit(1);
break;
default:
exit(0); // exit parent process with success
}
}
int main(int argc, char* argv[])
{
UNUSED(argc);
UNUSED(argv);
// 1. fork off the parent process
fork_process();
// 2. create new session
if (setsid() == -1) {
syslog(LOG_ERR, "ERROR while creating new session");
exit(1);
}
// 3. fork again to get rid of session leading process
fork_process();
// 4. capture all required signals
struct sigaction act = {
.sa_handler = catch_signal,
};
sigaction(SIGHUP, &act, NULL); // 1 - hangup
sigaction(SIGINT, &act, NULL); // 2 - terminal interrupt
sigaction(SIGQUIT, &act, NULL); // 3 - terminal quit
sigaction(SIGABRT, &act, NULL); // 6 - abort
sigaction(SIGTERM, &act, NULL); // 15 - termination
sigaction(SIGTSTP, &act, NULL); // 19 - terminal stop signal
// 5. update file mode creation mask
umask(0027);
// 6. change working directory to appropriate place
if (chdir("/opt") == -1) {
syslog(LOG_ERR, "ERROR while changing to working directory");
exit(1);
}
// 7. close all open file descriptors
for (int fd = sysconf(_SC_OPEN_MAX); fd >= 0; fd--) {
close(fd);
}
// 8. redirect stdin, stdout and stderr to /dev/null
if (open("/dev/null", O_RDWR) != STDIN_FILENO) {
syslog(LOG_ERR, "ERROR while opening '/dev/null' for stdin");
exit(1);
}
if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO) {
syslog(LOG_ERR, "ERROR while opening '/dev/null' for stdout");
exit(1);
}
if (dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) {
syslog(LOG_ERR, "ERROR while opening '/dev/null' for stderr");
exit(1);
}
// 9. option: open syslog for message logging
openlog(NULL, LOG_NDELAY | LOG_PID, LOG_DAEMON);
syslog(LOG_INFO, "Daemon has started...");
// 10. option: get effective user and group id for appropriate's one
struct passwd* pwd = getpwnam("daemon");
if (pwd == 0) {
syslog(LOG_ERR, "ERROR while reading daemon password file entry");
exit(1);
}
// 11. option: change root directory
if (chroot(".") == -1) {
syslog(LOG_ERR, "ERROR while changing to new root directory");
exit(1);
}
// 12. option: change effective user and group id for appropriate's one
if (setegid(pwd->pw_gid) == -1) {
syslog(LOG_ERR, "ERROR while setting new effective group id");
exit(1);
}
if (seteuid(pwd->pw_uid) == -1) {
syslog(LOG_ERR, "ERROR while setting new effective user id");
exit(1);
}
// 13. implement daemon body...
int t = 30;
do {
t = sleep(t);
} while (t > 0);
syslog(LOG_INFO,
"daemon stopped. Number of signals catched=%d\n",
signal_catched);
closelog();
return 0;
}
Makefile
EXE=daemon
SRCS=$(wildcard *.c)
CFLAGS=-Wall -Wextra -g -c -O0 -MD -std=gnu11
TOOLCHAIN_PATH=/buildroot/output/host/usr/bin/
TOOLCHAIN=$(TOOLCHAIN_PATH)aarch64-linux-
CFLAGS+=-mcpu=cortex-a53 -funwind-tables
##CFLAGS+=-O2 -fno-omit-frame-pointer
OBJDIR=.obj/nano
EXEC=$(EXE)
CC=$(TOOLCHAIN)gcc
LD=$(TOOLCHAIN)gcc
AR=$(TOOLCHAIN)ar
STRIP=$(TOOLCHAIN)strip
OBJDIR=.obj/$(target)
OBJS= $(addprefix $(OBJDIR)/, $(SRCS:.c=.o))
$(OBJDIR)/%o: %c
$(CC) $(CFLAGS) $< -o $@
all: $(OBJDIR)/ $(EXEC)
echo $(EXEC)
echo $(SRCS)
$(EXEC): $(OBJS) $(LINKER_SCRIPT)
$(LD) $(OBJS) $(LDFLAGS) -o $@
$(OBJDIR)/:
mkdir -p $(OBJDIR)
clean:
rm -Rf $(OBJDIR) $(EXEC) $(EXEC)_s *~
clean_all: clean
rm -Rf .obj $(EXE) $(EXE)_s $(EXE)_a $(EXE)_a_s $(EXE)_h $(EXE)_h_s
-include $(OBJS:.o=.d)
.PHONY: all clean clean_all
Threads
main.c
/**
* Copyright 2015 University of Applied Sciences Western Switzerland / Fribourg
*
* SPDX-License-Identifier: Apache-2.0
*
* Project: HEIA-FR / Embedded Systems Laboratory
*
* Abstract: Multi-threading
*
* Purpose: This module implements a simple multi-threading demo progam
*
* Autĥor Daniel Gachet / Jean-Roland Schuler
* Date: 17.11.2015
*/
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
// ----------------------------------------------------------------------------
// Macros and constants
// ----------------------------------------------------------------------------
#define ARRAY_OF(x) (sizeof(x) / sizeof(x[0]))
// ----------------------------------------------------------------------------
// Global variables
// ----------------------------------------------------------------------------
static pthread_t thread_id[3];
static bool is_running = true;
// ----------------------------------------------------------------------------
// Local threads
// ----------------------------------------int------------------------------------
void cleaner(void* p) { printf("%s: thread end\n", (char*)p); }
// ----------------------------------------------------------------------------
void* thread_1(void* arg)
{
pthread_cleanup_push(&cleaner, arg);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
while (is_running) {
printf(
"%s pid=%d, tid=%ld\n", (char*)arg, getpid(), syscall(SYS_gettid));
sleep(2);
}
pthread_cleanup_pop(1);
pthread_exit((void*)1);
return (void*)0;
}
// ----------------------------------------------------------------------------
void* thread_2(void* arg)
{
pthread_cleanup_push(cleaner, arg);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
while (is_running) {
printf(
"%s pid=%d, tid=%ld\n", (char*)arg, getpid(), syscall(SYS_gettid));
sleep(2);
}
pthread_cleanup_pop(0);
pthread_exit(0);
return (void*)2;
}
// ----------------------------------------------------------------------------
void* thread_3(void* arg)
{
while (is_running) {
printf(
"%s pid=%d, tid=%ld\n", (char*)arg, getpid(), syscall(SYS_gettid));
sleep(2);
}
return (void*)3;
}
// ----------------------------------------------------------------------------
// Local methods
// ----------------------------------------------------------------------------
static void catch_signal(int signal)
{
printf("signal = %d\n", signal);
pthread_cancel(thread_id[0]);
is_running = 0;
}
// ----------------------------------------------------------------------------
static void install_catch_signal()
{
struct sigaction act = {
.sa_handler = catch_signal,
};
sigemptyset(&act.sa_mask);
sigaction(SIGINT, &act, 0);
sigaction(SIGTSTP, &act, 0);
sigaction(SIGTERM, &act, 0);
sigaction(SIGABRT, &act, 0);
}
// ----------------------------------------------------------------------------
// Main program
// ----------------------------------------------------------------------------
int main(void)
{
install_catch_signal();
printf("Create threads... (pid=%d)\n", getpid());
pthread_create(&thread_id[0], NULL, thread_1, "thread_1");
pthread_create(&thread_id[1], NULL, thread_2, "thread_2");
pthread_create(&thread_id[2], NULL, thread_3, "thread_3");
printf("Wait until threads finished...\n");
printf("Type return to exit all threads\n");
getchar();
is_running = false;
for (int i = ARRAY_OF(thread_id) - 1; i >= 0; i--) {
void* return_msg;
pthread_join(thread_id[i], &return_msg);
printf("thread_%d terminated with %p\n", i + 1, return_msg);
}
printf("Program stops...\n");
return 0;
}
Makefile
EXE=threads
SRCS=$(wildcard *.c)
CFLAGS=-Wall -Wextra -g -c -O0 -MD -std=gnu11
LDFLAGS+=-lpthread
TOOLCHAIN_PATH=~/workspace/nano/buildroot/output/host/usr/bin/
TOOLCHAIN=$(TOOLCHAIN_PATH)aarch64-linux-
CFLAGS+=-mcpu=cortex-a53 -funwind-tables
##CFLAGS+=-O2 -fno-omit-frame-pointer
OBJDIR=.obj/nano
EXEC=$(EXE)
CC=$(TOOLCHAIN)gcc
LD=$(TOOLCHAIN)gcc
AR=$(TOOLCHAIN)ar
STRIP=$(TOOLCHAIN)strip
OBJDIR=.obj/$(target)
OBJS= $(addprefix $(OBJDIR)/, $(SRCS:.c=.o))
$(OBJDIR)/%o: %c
$(CC) $(CFLAGS) $< -o $@
all: $(OBJDIR)/ $(EXEC)
$(EXEC): $(OBJS) $(LINKER_SCRIPT)
$(LD) $(OBJS) $(LDFLAGS) -o $@
$(OBJDIR)/:
mkdir -p $(OBJDIR)
clean:
rm -Rf $(OBJDIR) $(EXEC) $(EXEC)_s *~
clean_all: clean
rm -Rf .obj $(EXE) $(EXE)_s $(EXE)_a $(EXE)_a_s $(EXE)_h $(EXE)_h_s
-include $(OBJS:.o=.d)
.PHONY: all clean clean_all