1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-29 11:41:21 +03:00

* sysdeps/pthread/aio_misc.h [!DONT_USE_BOOTSTRAP_MAP]

(struct waitlist): Don't add cond.
	* sysdeps/pthread/aio_notify.c [!DONT_USE_BOOTSTRAP_MAP]
	(__aio_notify): Use AIO_MISC_NOTIFY instead of pthread_cond_signal.
	* sysdeps/pthread/aio_suspend.c [!DONT_USE_BOOTSTRAP_MAP]: Don't
	use condvar, use AIO_MISC_WAIT.
	* sysdeps/pthread/lio_listio.c: Likewise.
	* rt/Makefile (tests): Add aio_suspend.
	* rt/tst-aio9.c: New file.
This commit is contained in:
Ulrich Drepper
2006-01-06 03:08:04 +00:00
parent 17041e4ff0
commit 679d83bac2
11 changed files with 312 additions and 19 deletions

View File

@ -1,5 +1,15 @@
2006-01-05 Ulrich Drepper <drepper@redhat.com> 2006-01-05 Ulrich Drepper <drepper@redhat.com>
* sysdeps/pthread/aio_misc.h [!DONT_USE_BOOTSTRAP_MAP]
(struct waitlist): Don't add cond.
* sysdeps/pthread/aio_notify.c [!DONT_USE_BOOTSTRAP_MAP]
(__aio_notify): Use AIO_MISC_NOTIFY instead of pthread_cond_signal.
* sysdeps/pthread/aio_suspend.c [!DONT_USE_BOOTSTRAP_MAP]: Don't
use condvar, use AIO_MISC_WAIT.
* sysdeps/pthread/lio_listio.c: Likewise.
* rt/Makefile (tests): Add aio_suspend.
* rt/tst-aio9.c: New file.
* rt/tst-aio3.c: The thread is now supposed to be created. * rt/tst-aio3.c: The thread is now supposed to be created.
2006-01-05 Roland McGrath <roland@redhat.com> 2006-01-05 Roland McGrath <roland@redhat.com>

View File

@ -1,3 +1,11 @@
2006-01-05 Ulrich Drepper <drepper@redhat.com>
* sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_futex_wait):
Return status.
(lll_futex_timed_wait): Define.
* sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise.
* sysdeps/pthread/aio_misc.h: New file.
2006-01-03 Joseph S. Myers <joseph@codesourcery.com> 2006-01-03 Joseph S. Myers <joseph@codesourcery.com>
* Makefile ($(objpfx)$(multidir)): Use mkdir -p. * Makefile ($(objpfx)$(multidir)): Use mkdir -p.

View File

@ -0,0 +1,73 @@
/* Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/* We define a special synchronization primitive for AIO. POSIX
conditional variables would be ideal but the pthread_cond_*wait
operations do not return on EINTR. This is a requirement for
correct aio_suspend and lio_listio implementations. */
#include <assert.h>
#include <pthreadP.h>
#include <lowlevellock.h>
#define DONT_NEED_AIO_MISC_COND 1
#define AIO_MISC_NOTIFY(waitlist) \
do { \
if (--*waitlist->counterp == 0) \
lll_futex_wake (waitlist->counterp, 1); \
} while (0)
#define AIO_MISC_WAIT(result, futex, timeout, cancel) \
do { \
int oldval = futex; \
\
if (oldval != 0) \
{ \
pthread_mutex_unlock (&__aio_requests_mutex); \
\
int oldtype; \
if (cancel) \
oldtype = LIBC_CANCEL_ASYNC (); \
\
int status; \
do \
{ \
status = lll_futex_timed_wait (&futex, oldval, timeout); \
if (status != -EWOULDBLOCK) \
break; \
\
oldval = futex; \
} \
while (oldval != 0); \
\
if (cancel) \
LIBC_CANCEL_RESET (oldtype); \
\
if (status == -EINTR) \
result = EINTR; \
else if (status == -ETIMEDOUT) \
result = EAGAIN; \
else \
assert (status == 0 || status == -EWOULDBLOCK); \
\
pthread_mutex_lock (&__aio_requests_mutex); \
} \
} while (0)
#include_next <aio_misc.h>

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. /* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
@ -66,17 +66,33 @@
#define lll_futex_wait(futex, val) \ #define lll_futex_wait(futex, val) \
do { \ ({ \
int __ignore; \ int __status; \
register __typeof (val) _val asm ("edx") = (val); \ register __typeof (val) _val asm ("edx") = (val); \
__asm __volatile (LLL_EBX_LOAD \ __asm __volatile (LLL_EBX_LOAD \
LLL_ENTER_KERNEL \ LLL_ENTER_KERNEL \
LLL_EBX_LOAD \ LLL_EBX_LOAD \
: "=a" (__ignore) \ : "=a" (__status) \
: "0" (SYS_futex), LLL_EBX_REG (futex), "S" (0), \ : "0" (SYS_futex), LLL_EBX_REG (futex), "S" (0), \
"c" (FUTEX_WAIT), "d" (_val), \ "c" (FUTEX_WAIT), "d" (_val), \
"i" (offsetof (tcbhead_t, sysinfo))); \ "i" (offsetof (tcbhead_t, sysinfo))); \
} while (0) __status; \
})
#define lll_futex_timed_wait(futex, val, timeout) \
({ \
int __status; \
register __typeof (val) _val asm ("edx") = (val); \
__asm __volatile (LLL_EBX_LOAD \
LLL_ENTER_KERNEL \
LLL_EBX_LOAD \
: "=a" (__status) \
: "0" (SYS_futex), LLL_EBX_REG (futex), "S" (timeout), \
"c" (FUTEX_WAIT), "d" (_val), \
"i" (offsetof (tcbhead_t, sysinfo))); \
__status; \
})
#define lll_futex_wake(futex, nr) \ #define lll_futex_wake(futex, nr) \

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. /* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
@ -47,16 +47,31 @@
#define lll_futex_wait(futex, val) \ #define lll_futex_wait(futex, val) \
do { \ ({ \
int __ignore; \ int __status; \
register __typeof (val) _val asm ("edx") = (val); \ register __typeof (val) _val asm ("edx") = (val); \
__asm __volatile ("xorq %%r10, %%r10\n\t" \ __asm __volatile ("xorq %%r10, %%r10\n\t" \
"syscall" \ "syscall" \
: "=a" (__ignore) \ : "=a" (__status) \
: "0" (SYS_futex), "D" (futex), "S" (FUTEX_WAIT), \ : "0" (SYS_futex), "D" (futex), "S" (FUTEX_WAIT), \
"d" (_val) \ "d" (_val) \
: "memory", "cc", "r10", "r11", "cx"); \ : "memory", "cc", "r10", "r11", "cx"); \
} while (0) __status; \
})
#define lll_futex_timed_wait(futex, val, timeout) \
({ \
register const struct timespec *__to __asm__ ("r10") = timeout; \
int __status; \
register __typeof (val) _val asm ("edx") = (val); \
__asm __volatile ("syscall" \
: "=a" (__status) \
: "0" (SYS_futex), "D" (futex), "S" (FUTEX_WAIT), \
"d" (_val), "r" (__to) \
: "memory", "cc", "r11", "cx"); \
__status; \
})
#define lll_futex_wake(futex, nr) \ #define lll_futex_wake(futex, nr) \

View File

@ -43,7 +43,8 @@ librt-routines = $(aio-routines) \
tests := tst-shm tst-clock tst-clock_nanosleep tst-timer tst-timer2 \ tests := tst-shm tst-clock tst-clock_nanosleep tst-timer tst-timer2 \
tst-aio tst-aio64 tst-aio2 tst-aio3 tst-aio4 tst-aio5 tst-aio6 \ tst-aio tst-aio64 tst-aio2 tst-aio3 tst-aio4 tst-aio5 tst-aio6 \
tst-aio7 tst-aio8 tst-mqueue1 tst-mqueue2 tst-mqueue3 tst-mqueue4 \ tst-aio7 tst-aio8 tst-aio9 \
tst-mqueue1 tst-mqueue2 tst-mqueue3 tst-mqueue4 \
tst-mqueue5 tst-mqueue6 tst-mqueue7 tst-mqueue8 tst-mqueue9 \ tst-mqueue5 tst-mqueue6 tst-mqueue7 tst-mqueue8 tst-mqueue9 \
tst-timer3 tst-timer4 tst-timer5 \ tst-timer3 tst-timer4 tst-timer5 \
tst-cpuclock1 tst-cpuclock2 \ tst-cpuclock1 tst-cpuclock2 \

124
rt/tst-aio9.c Normal file
View File

@ -0,0 +1,124 @@
#include <aio.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
static pthread_barrier_t b;
static pthread_t main_thread;
static int flag;
static void *
tf (void *arg)
{
int e = pthread_barrier_wait (&b);
if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
{
puts ("child: barrier_wait failed");
exit (1);
}
/* There is unfortunately no other way to try to make sure the other
thread reached the aio_suspend call. This test could fail on
highly loaded machines. */
sleep (2);
pthread_kill (main_thread, SIGUSR1);
while (1)
sleep (1000);
return NULL;
}
static void
sh (int sig)
{
flag = 1;
}
static int
do_test (void)
{
main_thread = pthread_self ();
struct sigaction sa;
sa.sa_handler = sh;
sa.sa_flags = 0;
sigemptyset (&sa.sa_mask);
if (sigaction (SIGUSR1, &sa, NULL) != 0)
{
puts ("sigaction failed");
return 1;
}
if (pthread_barrier_init (&b, NULL, 2) != 0)
{
puts ("barrier_init");
return 1;
}
int fds[2];
if (pipe (fds) != 0)
{
puts ("pipe failed");
return 1;
}
char buf[42];
struct aiocb req;
req.aio_fildes = fds[0];
req.aio_reqprio = 0;
req.aio_offset = 0;
req.aio_buf = buf;
req.aio_nbytes = sizeof (buf);
req.aio_sigevent.sigev_notify = SIGEV_NONE;
if (aio_read (&req) != 0)
{
puts ("aio_read failed");
return 1;
}
pthread_t th;
if (pthread_create (&th, NULL, tf, NULL) != 0)
{
puts ("create failed");
return 1;
}
int e = pthread_barrier_wait (&b);
if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
{
puts ("parent: barrier_wait failed");
exit (1);
}
const struct aiocb *list[1];
list[0] = &req;
e = aio_suspend (list, 1, NULL);
if (e != -1)
{
puts ("aio_suspend succeeded");
return 1;
}
if (errno != EINTR)
{
puts ("aio_suspend did not return EINTR");
return 1;
}
return 0;
}
#define TEST_FUNCTION do_test ()
#define TIMEOUT 5
#include "../test-skeleton.c"

View File

@ -47,7 +47,9 @@ struct waitlist
struct waitlist *next; struct waitlist *next;
/* The next two fields is used in synchronous `lio_listio' operations. */ /* The next two fields is used in synchronous `lio_listio' operations. */
#ifndef DONT_NEED_AIO_MISC_COND
pthread_cond_t *cond; pthread_cond_t *cond;
#endif
int *result; int *result;
volatile int *counterp; volatile int *counterp;

View File

@ -143,20 +143,24 @@ __aio_notify (struct requestlist *req)
{ {
struct waitlist *next = waitlist->next; struct waitlist *next = waitlist->next;
/* Decrement the counter. This is used in both cases. */
--*waitlist->counterp;
if (waitlist->sigevp == NULL) if (waitlist->sigevp == NULL)
{ {
if (waitlist->result != NULL && aiocbp->__return_value == -1) if (waitlist->result != NULL && aiocbp->__return_value == -1)
*waitlist->result = -1; *waitlist->result = -1;
#ifdef DONT_NEED_AIO_MISC_COND
AIO_MISC_NOTIFY (waitlist);
#else
/* Decrement the counter. */
--*waitlist->counterp;
pthread_cond_signal (waitlist->cond); pthread_cond_signal (waitlist->cond);
#endif
} }
else else
/* This is part of a asynchronous `lio_listio' operation. If /* This is part of a asynchronous `lio_listio' operation. If
this request is the last one, send the signal. */ this request is the last one, send the signal. */
if (*waitlist->counterp == 0) if (--*waitlist->counterp == 0)
{ {
#ifdef BROKEN_THREAD_SIGNALS #ifdef BROKEN_THREAD_SIGNALS
__aio_notify_only (waitlist->sigevp, waitlist->caller_pid); __aio_notify_only (waitlist->sigevp, waitlist->caller_pid);

View File

@ -44,7 +44,9 @@ struct clparam
const struct aiocb *const *list; const struct aiocb *const *list;
struct waitlist *waitlist; struct waitlist *waitlist;
struct requestlist **requestlist; struct requestlist **requestlist;
#ifndef DONT_NEED_AIO_MISC_COND
pthread_cond_t *cond; pthread_cond_t *cond;
#endif
int nent; int nent;
}; };
@ -52,6 +54,12 @@ struct clparam
static void static void
cleanup (void *arg) cleanup (void *arg)
{ {
#ifdef DONT_NEED_AIO_MISC_COND
/* Acquire the mutex. If pthread_cond_*wait is used this would
happen implicitly. */
pthread_mutex_lock (&__aio_requests_mutex);
#endif
const struct clparam *param = (const struct clparam *) arg; const struct clparam *param = (const struct clparam *) arg;
/* Now remove the entry in the waiting list for all requests /* Now remove the entry in the waiting list for all requests
@ -75,8 +83,10 @@ cleanup (void *arg)
*listp = (*listp)->next; *listp = (*listp)->next;
} }
#ifndef DONT_NEED_AIO_MISC_COND
/* Release the conditional variable. */ /* Release the conditional variable. */
(void) pthread_cond_destroy (param->cond); (void) pthread_cond_destroy (param->cond);
#endif
/* Release the mutex. */ /* Release the mutex. */
pthread_mutex_unlock (&__aio_requests_mutex); pthread_mutex_unlock (&__aio_requests_mutex);
@ -89,13 +99,21 @@ aio_suspend (list, nent, timeout)
int nent; int nent;
const struct timespec *timeout; const struct timespec *timeout;
{ {
if (__builtin_expect (nent < 0, 0))
{
__set_errno (EINVAL);
return -1;
}
struct waitlist waitlist[nent]; struct waitlist waitlist[nent];
struct requestlist *requestlist[nent]; struct requestlist *requestlist[nent];
#ifndef DONT_NEED_AIO_MISC_COND
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
#endif
int cnt; int cnt;
bool any = false; bool any = false;
int result = 0; int result = 0;
int dummy; int cntr = 1;
/* Request the mutex. */ /* Request the mutex. */
pthread_mutex_lock (&__aio_requests_mutex); pthread_mutex_lock (&__aio_requests_mutex);
@ -111,10 +129,12 @@ aio_suspend (list, nent, timeout)
if (requestlist[cnt] != NULL) if (requestlist[cnt] != NULL)
{ {
#ifndef DONT_NEED_AIO_MISC_COND
waitlist[cnt].cond = &cond; waitlist[cnt].cond = &cond;
#endif
waitlist[cnt].result = NULL; waitlist[cnt].result = NULL;
waitlist[cnt].next = requestlist[cnt]->waiting; waitlist[cnt].next = requestlist[cnt]->waiting;
waitlist[cnt].counterp = &dummy; waitlist[cnt].counterp = &cntr;
waitlist[cnt].sigevp = NULL; waitlist[cnt].sigevp = NULL;
#ifdef BROKEN_THREAD_SIGNALS #ifdef BROKEN_THREAD_SIGNALS
waitlist[cnt].caller_pid = 0; /* Not needed. */ waitlist[cnt].caller_pid = 0; /* Not needed. */
@ -140,12 +160,17 @@ aio_suspend (list, nent, timeout)
.list = list, .list = list,
.waitlist = waitlist, .waitlist = waitlist,
.requestlist = requestlist, .requestlist = requestlist,
#ifndef DONT_NEED_AIO_MISC_COND
.cond = &cond, .cond = &cond,
#endif
.nent = nent .nent = nent
}; };
pthread_cleanup_push (cleanup, &clparam); pthread_cleanup_push (cleanup, &clparam);
#ifdef DONT_NEED_AIO_MISC_COND
AIO_MISC_WAIT (result, cntr, timeout, 1);
#else
if (timeout == NULL) if (timeout == NULL)
result = pthread_cond_wait (&cond, &__aio_requests_mutex); result = pthread_cond_wait (&cond, &__aio_requests_mutex);
else else
@ -167,6 +192,7 @@ aio_suspend (list, nent, timeout)
result = pthread_cond_timedwait (&cond, &__aio_requests_mutex, result = pthread_cond_timedwait (&cond, &__aio_requests_mutex,
&abstime); &abstime);
} }
#endif
pthread_cleanup_pop (0); pthread_cleanup_pop (0);
} }
@ -190,19 +216,23 @@ aio_suspend (list, nent, timeout)
*listp = (*listp)->next; *listp = (*listp)->next;
} }
#ifndef DONT_NEED_AIO_MISC_COND
/* Release the conditional variable. */ /* Release the conditional variable. */
if (__builtin_expect (pthread_cond_destroy (&cond) != 0, 0)) if (__builtin_expect (pthread_cond_destroy (&cond) != 0, 0))
/* This must never happen. */ /* This must never happen. */
abort (); abort ();
#endif
if (result != 0) if (result != 0)
{ {
/* An error occurred. Possibly it's EINTR. We have to translate #ifndef DONT_NEED_AIO_MISC_COND
/* An error occurred. Possibly it's ETIMEDOUT. We have to translate
the timeout error report of `pthread_cond_timedwait' to the the timeout error report of `pthread_cond_timedwait' to the
form expected from `aio_suspend'. */ form expected from `aio_suspend'. */
if (result == ETIMEDOUT) if (result == ETIMEDOUT)
__set_errno (EAGAIN); __set_errno (EAGAIN);
else else
#endif
__set_errno (result); __set_errno (result);
result = -1; result = -1;

View File

@ -122,9 +122,11 @@ lio_listio_internal (int mode, struct aiocb *const list[], int nent,
} }
else if (LIO_MODE (mode) == LIO_WAIT) else if (LIO_MODE (mode) == LIO_WAIT)
{ {
#ifndef DONT_NEED_AIO_MISC_COND
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
struct waitlist waitlist[nent];
int oldstate; int oldstate;
#endif
struct waitlist waitlist[nent];
total = 0; total = 0;
for (cnt = 0; cnt < nent; ++cnt) for (cnt = 0; cnt < nent; ++cnt)
@ -133,7 +135,9 @@ lio_listio_internal (int mode, struct aiocb *const list[], int nent,
if (requests[cnt] != NULL && list[cnt]->aio_lio_opcode != LIO_NOP) if (requests[cnt] != NULL && list[cnt]->aio_lio_opcode != LIO_NOP)
{ {
#ifndef DONT_NEED_AIO_MISC_COND
waitlist[cnt].cond = &cond; waitlist[cnt].cond = &cond;
#endif
waitlist[cnt].result = &result; waitlist[cnt].result = &result;
waitlist[cnt].next = requests[cnt]->waiting; waitlist[cnt].next = requests[cnt]->waiting;
waitlist[cnt].counterp = &total; waitlist[cnt].counterp = &total;
@ -146,6 +150,9 @@ lio_listio_internal (int mode, struct aiocb *const list[], int nent,
} }
} }
#ifdef DONT_NEED_AIO_MISC_COND
AIO_MISC_WAIT (result, total, NULL, 0);
#else
/* Since `pthread_cond_wait'/`pthread_cond_timedwait' are cancellation /* Since `pthread_cond_wait'/`pthread_cond_timedwait' are cancellation
points we must be careful. We added entries to the waiting lists points we must be careful. We added entries to the waiting lists
which we must remove. So defer cancellation for now. */ which we must remove. So defer cancellation for now. */
@ -161,6 +168,7 @@ lio_listio_internal (int mode, struct aiocb *const list[], int nent,
if (pthread_cond_destroy (&cond) != 0) if (pthread_cond_destroy (&cond) != 0)
/* This must never happen. */ /* This must never happen. */
abort (); abort ();
#endif
/* If any of the I/O requests failed, return -1 and set errno. */ /* If any of the I/O requests failed, return -1 and set errno. */
if (result != 0) if (result != 0)
@ -193,7 +201,9 @@ lio_listio_internal (int mode, struct aiocb *const list[], int nent,
if (requests[cnt] != NULL if (requests[cnt] != NULL
&& list[cnt]->aio_lio_opcode != LIO_NOP) && list[cnt]->aio_lio_opcode != LIO_NOP)
{ {
#ifndef DONT_NEED_AIO_MISC_COND
waitlist->list[cnt].cond = NULL; waitlist->list[cnt].cond = NULL;
#endif
waitlist->list[cnt].result = NULL; waitlist->list[cnt].result = NULL;
waitlist->list[cnt].next = requests[cnt]->waiting; waitlist->list[cnt].next = requests[cnt]->waiting;
waitlist->list[cnt].counterp = &waitlist->counter; waitlist->list[cnt].counterp = &waitlist->counter;