On Tue, Aug 13, 2013 at 6:27 AM, David Matthews <David.Matthews at prolingua.co.uk> wrote:
Hi Dmitry, I discovered a problem with the code that I added and I have had to remove some of it. In the callback code there is a check to see if the thread has ever been in ML code before and if not Poly creates some data structures for it which includes an ML stack. The difficulty is in knowing when to remove this data. Threads created by Poly always call an "exit" function and that removes the data for those threads but it's not possible to use that for threads created by foreign code. I added some code to the "main" thread to try to detect when a thread has exited but that caused crashes. It seems that, unlike with Windows, there is no safe way to discover when a thread created with pthreads has exited. The simplest possibility would be to remove the data and the ML stack as soon as the callback returns, if that callback created the data. If your thread is making many calls to the callback that could be expensive. Would that be a problem for your code?
Regards, David
There is a way to detect pthread exit. Create a pthread_key_t with a non-NULL destructor function, and set the value of that key to something non-NULL when a thread enters ML code for the first time. When that thread exits, the destructor function will be called. I whipped up an overly simplistic example to illustrate the approach. (Don't be too critical; I pumped this out pretty quickly.)
#include <errno.h> #include <pthread.h> #include <stdlib.h> #include <stdio.h> #include <time.h>
static pthread_key_t key; static struct timespec sleep_time;
static void usage (const char *progname) { fprintf (stderr, "Usage: %s num_threads\n\ where num_threads is between 0 and 1000, exclusive\n", progname); }
static void key_destructor (void *value) { printf ("This is thread %zu signing off!\n", (size_t) value); }
static void * child_function (void *arg) { pthread_setspecific (key, arg); printf ("Thread %zu sleeping for 1 second\n", (size_t) arg); nanosleep (&sleep_time, NULL); printf ("Thread %zu exiting\n", (size_t) arg); return NULL; }
int main (int argc, char *argv[]) { pthread_t *children; size_t i, num_children; int err;
if (argc != 2) { usage (argv[0]); return EXIT_FAILURE; }
sleep_time.tv_sec = 1L; sleep_time.tv_nsec = 0L;
num_children = atoi (argv[1]); if (num_children < 1 || num_children > 999) { usage (argv[0]); return EXIT_FAILURE; } children = (pthread_t *) calloc (num_children, sizeof (*children)); if (children == NULL) { fputs ("Out of memory.\n", stderr); return EXIT_FAILURE; }
err = pthread_key_create (&key, key_destructor); if (err != 0) { errno = err; printf ("pthread_key_create: %m\n"); free (children); return EXIT_FAILURE; }
for (i = 0U; i < num_children; i++) pthread_create (&children[i], NULL, child_function, (void *)i); for (i = 0U; i < num_children; i++) pthread_join (children[i], NULL); nanosleep (&sleep_time, NULL);
pthread_key_delete (key); free (children); return EXIT_SUCCESS; }
Regards,