COMS 4995 Advanced Systems Programming

Index of 2024-1/code/12

Parent directory
Makefile
fork.c
mm-test.c
pthread.c
sig1.c
sig2.c
tls.c

Makefile

CC = gcc
CFLAGS = -g -Wall
LDFLAGS = -pthread

.PHONY: default
default: pthread fork tls sig1 sig2

pthread:

fork:

sig1:

sig2:

tls:

.PHONY: clean
clean:
	rm -f *.o pthread fork sig1 sig2 tls

fork.c

#include <stddef.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc, char **argv) {
    pid_t pid;
    if ((pid = fork()) > 0) {
        waitpid(pid, NULL, 0);
    }
}

mm-test.c

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <pthread.h>

#include "mm.h"

void inc(uint64_t *val) {
    for (int i = 0; i < 1e7; i++)
        ++*val;
    printf("%lu\n", *val);
}

void* inc_thread(void *v) {
    inc(v);
    return NULL;
}

int main(int argc, char **argv)
{
    mm_init();

    void *unused = mm_malloc(32);
    uint64_t *p = mm_malloc(8);
    uint64_t *q = mm_malloc(8);

    mm_checkheap(1);

    // Single-threaded
    inc(p);
    inc(q);

#if 0
    // Multi-threaded
    pthread_t t1, t2;
    pthread_create(&t1, NULL, &inc_thread, p);
    pthread_create(&t2, NULL, &inc_thread, q);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
#endif

    mm_free(p);
    mm_free(q);
    mm_free(unused);
    mm_deinit();
}

pthread.c

#include <pthread.h>

void *noop(void *arg) {
    return NULL;
}

int main(int argc, char **argv) {
    pthread_t thread;
    pthread_create(&thread, NULL, &noop, NULL);
    pthread_join(thread, NULL);
    return 0;
}

sig1.c

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

int sig = 0;

void handler(int signo) { sig = signo; }

#define handle_error_en(en, msg) \
    do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

static void *sig_thread(void *arg) {
    int s;
    sigset_t *set = arg;

    /* Unblock SIGUSR1 and SIGQUIT for this thread */
    s = pthread_sigmask(SIG_UNBLOCK, set, NULL);
    if (s != 0)
        handle_error_en(s, "pthread_sigmask");

    /* Race condition: you can miss a signal here. Alternatively, use
     * sigsuspend() for atomic signal unblock and pause() */

    for (;;) {
        pause();
        printf("Signal handling thread got signal %d\n", sig);
    }

    return NULL;
}

int main(int argc, char *argv[]) {
    pthread_t thread;
    sigset_t set;
    int s;

    /* Block SIGUSR1 and SIGQUIT */
    sigemptyset(&set);
    sigaddset(&set, SIGQUIT);
    sigaddset(&set, SIGUSR1);
    s = pthread_sigmask(SIG_BLOCK, &set, NULL);
    if (s != 0)
        handle_error_en(s, "pthread_sigmask");

    /* Install handlers for SIGQUIT and SIGUSR1 */
    struct sigaction act;
    act.sa_handler = handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    sigaction(SIGUSR1, &act, NULL);
    sigaction(SIGQUIT, &act, NULL);

    s = pthread_create(&thread, NULL, &sig_thread, &set);
    if (s != 0)
        handle_error_en(s, "pthread_create");

    /* Main thread carries on to create other threads and/or do
       other work */

    pause();            /* Dummy pause so we can test program */
}

sig2.c

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

#define handle_error_en(en, msg) \
    do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

static void *sig_thread(void *arg) {
    sigset_t *set = arg;
    int s, sig;

    for (;;) {
        /* sigwait() consumes a pending signal */
        s = sigwait(set, &sig);
        if (s != 0)
            handle_error_en(s, "sigwait");
        printf("Signal handling thread got signal %d\n", sig);
    }
    return NULL;
}

int main(int argc, char *argv[]) {
    pthread_t thread;
    sigset_t set;
    int s;

    /* Block SIGUSR1 and SIGQUIT; other threads created by main()
       will inherit a copy of the signal mask. */
    sigemptyset(&set);
    sigaddset(&set, SIGUSR1);
    sigaddset(&set, SIGQUIT);
    s = pthread_sigmask(SIG_BLOCK, &set, NULL);
    if (s != 0)
        handle_error_en(s, "pthread_sigmask");

    s = pthread_create(&thread, NULL, &sig_thread, &set);
    if (s != 0)
        handle_error_en(s, "pthread_create");


    /* Main thread carries on to create other threads and/or do
       other work */

    pause();            /* Dummy pause so we can test program */
}

tls.c

#include <stdio.h>
#include <stdint.h>
#include <pthread.h>

// Global variable shared by all threads
uint64_t x = 0;

// Thread local global variable
__thread uint64_t y = 0;

void *inc_and_print(void *unused) {
    for (int i = 0; i < 1e7; i++) {
        x++;
        y++;
    }

    printf("x=%lu, y=%lu\n", x, y);
    return NULL;
}

int main(int argc, char **argv) {
    pthread_t threads[2];
    pthread_create(&threads[0], NULL, &inc_and_print, NULL);
    pthread_create(&threads[1], NULL, &inc_and_print, NULL);

    pthread_join(threads[0], NULL);
    pthread_join(threads[1], NULL);

    return 0;
}