Skip to content

Instantly share code, notes, and snippets.

@colematt
Last active February 9, 2022 17:50
Show Gist options
  • Save colematt/596de75f5c2f3665e14fb3efea64723b to your computer and use it in GitHub Desktop.
Save colematt/596de75f5c2f3665e14fb3efea64723b to your computer and use it in GitHub Desktop.
[Storing pointers in Thread-Specific Storage across process boundaries] #tss #pthreads #linux
PWD := $(shell pwd)
CFLAGS := -g -Wall
LDFLAGS := -L=. -Wl,-rpath=.
all: tss-fork
tss-fork: tss-fork.c
$(CC) $(CFLAGS) tss-fork.c -o tss-fork -pthread
.PHONY: clean
clean:
rm -fv tss-fork
rm -fv *.o *~
#include <pthread.h> //pthread_key_t, pthread_key_* and pthread_*specific
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h> //pid_t
#include <sys/wait.h> //wait()
#include <unistd.h> //fork(), wait()
typedef struct map_t {
void *keys[16];
void *values[16];
} map_t;
int main(int argc, char const *argv[]) {
pthread_key_t key;
void *val;
int ret;
pid_t pid;
/* key create without destructor */
ret = pthread_key_create(&key, NULL);
printf("pthread_key_create ret: %d, key: %u\n", ret, (unsigned int)key);
/* allocate a map_t on heap */
map_t *my_map = malloc(sizeof(map_t));
printf("my_map address: %p\n", my_map);
/* key previously created, set TSS value at key */
val = (void *)my_map;
ret = pthread_setspecific(key, val);
printf("pthread_setspecific ret: %d\n", ret);
/* Demonstrate that we can recover the key */
val = NULL;
printf("Clear val: %p\n", val);
val = pthread_getspecific(key);
printf("Get val: %p\n", val);
/* Do keys work across fork boundaries?*/
val = NULL;
printf("Clear val before forking: %p\n", val);
pid = fork();
if (pid == 0) {
/* child */
val = pthread_getspecific(key);
pid = getpid();
printf("Child(%d) got val: %p\n", pid, val);
// Child waits 5 seconds, tries to access the slot.
//(Parent should have deleted the key by now)
sleep(5);
val = NULL;
val = pthread_getspecific(key);
printf("Child(%d) gets val after parent deleted its key? %s (%p)\n", pid,
val != NULL ? "Yes!" : "No!", val);
// Child resets tss[key], then deletes its key.
ret = pthread_setspecific(key, NULL);
ret = pthread_key_delete(key);
printf("Child(%d): pthread_key_delete ret: %d\n", pid, ret);
exit(0);
} else {
/* parent */
val = pthread_getspecific(key);
pid = getpid();
printf("Parent(%d) got val: %p\n", pid, val);
// Parent waits 2 seconds to allow child to perform lines 46-48,
// then deletes the key and waits for child to exit.
sleep(2);
/* Parent resets its tss[key], then deletes key */
ret = pthread_setspecific(key, NULL);
ret = pthread_key_delete(key);
printf("Parent(%d): pthread_key_delete ret: %d\n", pid, ret);
// Wait for child process
wait(&ret);
printf("Parent(%d): Child exited with value %d\n", pid, ret);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment