Last active
February 9, 2022 17:50
-
-
Save colematt/596de75f5c2f3665e14fb3efea64723b to your computer and use it in GitHub Desktop.
[Storing pointers in Thread-Specific Storage across process boundaries] #tss #pthreads #linux
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 *~ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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