diff options
author | Roland McGrath <roland@gnu.org> | 2002-12-09 07:14:24 +0000 |
---|---|---|
committer | Roland McGrath <roland@gnu.org> | 2002-12-09 07:14:24 +0000 |
commit | 57b4cb25227fbb4c4e379877de27a5aa119ba938 (patch) | |
tree | 4c8421495260dec7a0249e39a0ad99d09925a19d /sysdeps/pthread/aio_notify.c | |
parent | 531da978ceb31fdb28c5f0fdd9604004b765d9b1 (diff) | |
download | glibc-57b4cb25227fbb4c4e379877de27a5aa119ba938.zip glibc-57b4cb25227fbb4c4e379877de27a5aa119ba938.tar.gz glibc-57b4cb25227fbb4c4e379877de27a5aa119ba938.tar.bz2 |
* sysdeps/pthread/aio_notify.c (notify_func_wrapper): Take a malloc'd
struct containing function ptr and value, free it.
(__aio_notify_only): Allocate that and copy values from SIGEV into it.
It's not safe to let the new thread use the SIGEV pointer.
Diffstat (limited to 'sysdeps/pthread/aio_notify.c')
-rw-r--r-- | sysdeps/pthread/aio_notify.c | 33 |
1 files changed, 30 insertions, 3 deletions
diff --git a/sysdeps/pthread/aio_notify.c b/sysdeps/pthread/aio_notify.c index 4537ca5..047b631 100644 --- a/sysdeps/pthread/aio_notify.c +++ b/sysdeps/pthread/aio_notify.c @@ -25,11 +25,20 @@ #include "aio_misc.h" +struct notify_func + { + void (*func) (sigval_t); + sigval_t value; + }; + static void * notify_func_wrapper (void *arg) { - struct sigevent *sigev = arg; - sigev->sigev_notify_function (sigev->sigev_value); + struct notify_func *const n = arg; + void (*func) (sigval_t) = n->func; + sigval_t value = n->value; + free (n); + (*func) (value); return NULL; } @@ -55,8 +64,26 @@ __aio_notify_only (struct sigevent *sigev, pid_t caller_pid) pattr = &attr; } - if (pthread_create (&tid, pattr, notify_func_wrapper, sigev) < 0) + /* SIGEV may be freed as soon as we return, so we cannot let the + notification thread use that pointer. Even though a sigval_t is + only one word and the same size as a void *, we cannot just pass + the value through pthread_create as the argument and have the new + thread run the user's function directly, because on some machines + the calling convention for a union like sigval_t is different from + that for a pointer type like void *. */ + struct notify_func *nf = malloc (sizeof *nf); + if (nf == NULL) result = -1; + else + { + nf->func = sigev->sigev_notify_function; + nf->value = sigev->sigev_value; + if (pthread_create (&tid, pattr, notify_func_wrapper, nf) < 0) + { + free (nf); + result = -1; + } + } } else if (sigev->sigev_notify == SIGEV_SIGNAL) { |