aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/pthread/aio_notify.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2002-12-09 07:14:24 +0000
committerRoland McGrath <roland@gnu.org>2002-12-09 07:14:24 +0000
commit57b4cb25227fbb4c4e379877de27a5aa119ba938 (patch)
tree4c8421495260dec7a0249e39a0ad99d09925a19d /sysdeps/pthread/aio_notify.c
parent531da978ceb31fdb28c5f0fdd9604004b765d9b1 (diff)
downloadglibc-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.c33
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)
{