Aller au contenu

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

Berkeley Sockets

Protocole orienté connexion (TCP)

Etcher

Appels systèmes "Socket" pour un protocole orienté connexion (TCP)

Protocole sans connexion (UDP)

Etcher

Appels systèmes "Socket" pour un protocole sans connexion (UDP)