diff options
Diffstat (limited to 'rtkaio')
134 files changed, 4427 insertions, 0 deletions
diff --git a/rtkaio/Banner b/rtkaio/Banner new file mode 100644 index 0000000000..1037d5d423 --- /dev/null +++ b/rtkaio/Banner @@ -0,0 +1 @@ +RT using linux kernel aio diff --git a/rtkaio/ChangeLog b/rtkaio/ChangeLog new file mode 100644 index 0000000000..b5033f6336 --- /dev/null +++ b/rtkaio/ChangeLog @@ -0,0 +1,235 @@ +2006-09-15 Jakub Jelinek <jakub@redhat.com> + + [BZ #3138] + * rt/tst-aiod.c (do_prepare): Give name_len type size_t. + * rt/tst-aiod64.c (do_prepare): Likewise. + +2006-09-07 Jakub Jelinek <jakub@redhat.com> + + * tst-aiod2.c: Adjust test for new semantics of lio_listio. + * tst-aiod3.c: The thread is now supposed to be created. + + * Makefile: Use $(..) in place of ../. + (tests): Add tst-aio{8,9,10}, tst-cpuclock{1,2}, tst-cputimer{1,2,3} + and tst-clock2. + (CPPFLAGS-librtkaio): Append -I$(..)rt. + * Versions.def (librtkaio): Add GLIBC_2.4 version. + * sysdeps/unix/sysv/linux/kaio_misc.c (wait_for_kernel_requests) + [!DONT_NEED_AIO_MISC_COND]: Don't use condvar, use AIO_MISC_WAIT. + * sysdeps/unix/sysv/linux/kaio_misc.h [HAVE_FORCED_UNWIND] + (DONT_NEED_AIO_MISC_COND, AIO_MISC_NOTIFY, AIO_MISC_WAIT): Define. + (struct waitlist) [DONT_NEED_AIO_MISC_COND]: Remove cond. + * sysdeps/unix/sysv/linux/kaio_suspend.c (struct clparam) + [DONT_NEED_AIO_MISC_COND]: Remove cond. + (cleanup) [DONT_NEED_AIO_MISC_COND]: Lock __aio_requests_mutex on + entry. Don't destroy param->cond. + (aio_suspend): Fail if nent is negative. + (aio_suspend) [DONT_NEED_AIO_MISC_COND]: Don't use cond, use + AIO_MISC_WAIT. + * sysdeps/unix/sysv/linux/klio_listio.c (lio_listio): Renamed to... + (lio_listio_internal): ... this. Don't use cond, but AIO_MISC_WAIT, + if DONT_NEED_AIO_MISC_COND. Remove mode parameter check. Only set + sigevent type to SIGEV_NONE if LIO_NO_INDIVIDUAL_EVENT is set. + (__lio_listio_21): New function. Compatiblity version which sets + LIO_NO_INDIVIDUAL_EVENT before calling lio_listio_internal. + (__lio_listio_item_notify): New function. + * sysdeps/unix/sysv/linux/klio_listio64.c: Define __lio_listio_21 and + __lio_listio_item_notify macros. + * aio.h: Removed. + * configure.in: New file + * configure: Regenerated. + * sysdeps/rtkaio/kaio_cancel.c: Moved to... + * kaio_cancel.c: ... here. New file. + * sysdeps/rtkaio/kaio_error.c: Moved to... + * kaio_error.c: ... here. New file. + * sysdeps/rtkaio/kaio_fsync.c: Moved to... + * kaio_fsync.c: ... here. New file. + * sysdeps/rtkaio/kaio_misc.c: Moved to... + * kaio_misc.c: ... here. New file. + * sysdeps/rtkaio/kaio_notify.c: Moved to... + * kaio_notify.c: ... here. New file. + * sysdeps/rtkaio/kaio_read.c: Moved to... + * kaio_read.c: ... here. New file. + * sysdeps/rtkaio/kaio_read64.c: Moved to... + * kaio_read64.c: ... here. New file. + * sysdeps/rtkaio/kaio_return.c: Moved to... + * kaio_return.c: ... here. New file. + * sysdeps/rtkaio/kaio_sigqueue.c: Moved to... + * kaio_sigqueue.c: ... here. New file. + * sysdeps/rtkaio/kaio_suspend.c: Moved to... + * kaio_suspend.c: ... here. New file. + * sysdeps/rtkaio/kaio_write.c: Moved to... + * kaio_write.c: ... here. New file. + * sysdeps/rtkaio/kaio_write64.c: Moved to... + * kaio_write64.c: ... here. New file. + * sysdeps/rtkaio/klio_listio.c: Moved to... + * klio_listio.c: ... here. New file. + * sysdeps/rtkaio/klio_listio64.c: Moved to... + * klio_listio64.c: ... here. New file. + * sysdeps/pthread/Versions: New file. + * tst-aio8.c: New file. + * tst-aio9.c: New file. + * tst-aio10.c: New file. + * tst-clock2.c: New file. + * tst-cpuclock1.c: New file. + * tst-cpuclock2.c: New file. + * tst-cputimer1.c: New file. + * tst-cputimer2.c: New file. + * tst-cputimer3.c: New file. + * sysdeps/unix/sysv/linux/sparc/Makefile: New file. + * sysdeps/unix/sysv/linux/sparc/rtkaio-sysdep.c: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/Versions: New file. + * sysdeps/mips/Makefile: Removed. + * sysdeps/unix/mips/rtkaio-sysdep.S: Removed. + * sysdeps/unix/sysv/linux/hppa/Versions: Removed. + * sysdeps/unix/sysv/linux/hppa/kaio_cancel.c: Removed. + +2006-07-19 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/kaio_misc.c: Include atomic.h. + (kernel_callback): Ensure __return_value is updated before + __error_code is set. + +2006-05-11 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-mqueue{8,9}, tst-timer5 and + tst-aiod{,64,2,3,4,5}. + (LDFLAGS-rtkaio.so): Add -Wl,--enable-new-dtags,-z,nodelete. + * sysdeps/unix/sysv/linux/kaio_misc.h: Include signal.h and + sysdep.h. + (aio_start_notify_thread, aio_create_helper_thread): Define + for !BROKEN_THREAD_SIGNALS. + (__aio_start_notify_thread, __aio_create_helper_thread): New + functions for !BROKEN_THREAD_SIGNALS. + * sysdeps/unix/sysv/linux/kaio_misc.c: Include sys/sysmacros.h. + (aio_create_helper_thread): Define if not yet defined. + (__aio_create_helper_thread): New function. + (__aio_wait_for_events): Pass 1 rather than 0 as min_nr to + io_getevents. + (handle_kernel_aio): Likewise. + (__aio_create_kernel_thread): Use aio_create_helper_thread. + (__aio_enqueue_user_request): Likewise. + (handle_fildes_io): Likewise. Remove noreturn attribute, + return NULL instead of calling pthread_exit (NULL). + (__aio_enqueue_request_ctx): Call fcntl and fxstat64 to avoid using + kaio on non-O_DIRECT non-/dev/raw* filedescriptors. For LIO_SYNC + and LIO_DSYNC also set kctx to KCTX_NONE. + * sysdeps/unix/sysv/linux/kaio_suspend.c (aio_suspend): Don't start + handle_kernel_aio thread if ktotal is zero. + * sysdeps/pthread/Makefile (tests): Add tst-mqueue8x. + (CFLAGS-tst-mqueue8x.c): Add -fexceptions. + * Versions.def (librtkaio): Add GLIBC_2.3.4 version. + * kaio_mq_close.c: New file. + * kaio_mq_getattr.c: New file. + * kaio_mq_notify.c: New file. + * kaio_mq_open.c: New file. + * kaio_mq_receive.c: New file. + * kaio_mq_send.c: New file. + * kaio_mq_setattr.c: New file. + * kaio_mq_timedreceive.c: New file. + * kaio_mq_timedsend.c: New file. + * kaio_mq_unlink.c: New file. + * sysdeps/pthread/tst-mqueue8x.c: New file. + * sysdeps/unix/sysv/linux/syscalls.list: New file. + * tst-mqueue8.c: New file. + * tst-mqueue9.c: New file. + * tst-timer5.c: New file. + * tst-aiod.h: New file. + * tst-aiod.c: New test. + * tst-aiod64.c: New test. + * tst-aiod2.c: New test. + * tst-aiod3.c: New test. + * tst-aiod4.c: New test. + * tst-aiod5.c: New test. + * sysdeps/mips/Makefile: New file. + * sysdeps/unix/alpha/Makefile: New file. + * sysdeps/unix/alpha/rtkaio-sysdep.S: New file. + * sysdeps/unix/mips/rtkaio-sysdep.S: New file. + * sysdeps/unix/sysv/linux/Makefile: New file. + * sysdeps/unix/sysv/linux/s390/Makefile: New file. + * sysdeps/unix/sysv/linux/s390/rtkaio-sysdep.S: New file. + * sysdeps/unix/sysv/linux/powerpc/Makefile: New file. + * sysdeps/unix/sysv/linux/powerpc/rtkaio-sysdep.c: New file. + * sysdeps/unix/sysv/linux/ia64/Makefile: New file. + * sysdeps/unix/sysv/linux/ia64/rtkaio-sysdep.S: New file. + +2004-04-17 Jakub Jelinek <jakub@redhat.com> + + * rt/Makefile (mq-routines): Set. + (librt-routines): Use it. + (tests): Add tst-mqueue{1,2,3,4,5,6,7} and tst-timer{3,4}. + (tst-mqueue7-ARGS): Set. + * rt/Versions (librt): Add mq_*@@GLIBC_2.3.4. + * rt/tst-mqueue1.c: New file. + * rt/tst-mqueue2.c: New file. + * rt/tst-mqueue3.c: New file. + * rt/tst-mqueue4.c: New file. + * rt/tst-mqueue5.c: New file. + * rt/tst-mqueue6.c: New file. + * rt/tst-mqueue7.c: New file. + * rt/tst-timer3.c: New file. + * rt/tst-timer4.c: New file. + +2003-08-14 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/kaio_misc.c (wait_for_kernel_requests): + New function. + (handle_fildes_io): Use it for LIO_SYNC and LIO_DSYNC. + + * sysdeps/pthread/Makefile (CPPFLAGS): Add -DBROKEN_THREAD_SIGNALS + for rtkaio/linuxthreads combo. + * sysdeps/unix/sysv/linux/kaio_misc.c (__aio_enqueue_request_ctx): + Only set caller_pid if BROKEN_THREAD_SIGNALS. + * sysdeps/unix/sysv/linux/kaio_misc.h (struct waitlist, + struct requestlist): Remove caller_pid unless BROKEN_THREAD_SIGNALS. + (__aio_notify_only): Remove last argument if not + BROKEN_THREAD_SIGNALS. + * sysdeps/unix/sysv/linux/kaio_suspend.c (aio_suspend): Only set + caller_pid if not BROKEN_THREAD_SIGNALS. + * sysdeps/unix/sysv/linux/klio_listio.c (lio_listio): Likewise. + Remove last argument in call to __aio_notify_only unless + BROKEN_THREAD_SIGNALS. + + * tst-aio.c: Avoid test duplication. Include rt/aio.c instead. + * tst-aio2.c: Similarly. + * tst-aio3.c: Similarly. + * tst-aio4.c: Similarly. + * tst-aio5.c: Similarly. + * tst-aio6.c: Similarly. + * tst-aio64.c: Similarly. + * tst-aio7.c: Similarly. + * tst-clock.c: Similarly. + * tst-clock_nanosleep.c: Similarly. + * tst-shm.c: Similarly. + * tst-timer2.c: Similarly. + +2003-07-29 Roland McGrath <roland@redhat.com> + + * rt/tst-timer2.c: New file. + * rt/Makefile (tests): Add it. + +2003-07-25 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/kaio_cancel.c (aio_cancel): Attempt + to cancel kioctx != KCTX_NONE requests even if second argument + to aio_cancel is NULL. + +2003-07-24 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/kaio_cancel.c (aio_cancel): Return + AIO_ALLDONE if aiocbp != NULL and has already completed. Return + -1/EINVAL if aiocbp->aio_fildes does not match fildes. + + * sysdeps/unix/sysv/linux/alpha/kaio_cancel.c: New file. + * sysdeps/unix/sysv/linux/hppa/kaio_cancel.c: New file. + * sysdeps/unix/sysv/linux/sparc/kaio_cancel.c: New file. + * sysdeps/unix/sysv/linux/kaio_cancel.c (aio_cancel): Attempt + to cancel request handled by kernel (so far just if aiocbp != NULL). + * sysdeps/unix/sysv/linux/kaio_misc.c (__aio_remove_krequest): Fix + assertion, req->kioctx must NOT be KCTX_NONE. + * sysdeps/unix/sysv/linux/kaio_misc.h (__aio_remove_krequest): New + prototype. + +2003-07-23 Jakub Jelinek <jakub@redhat.com> + + * New add-on. diff --git a/rtkaio/Depend b/rtkaio/Depend new file mode 100644 index 0000000000..b35b8e20d9 --- /dev/null +++ b/rtkaio/Depend @@ -0,0 +1 @@ +rt diff --git a/rtkaio/Makefile b/rtkaio/Makefile new file mode 100644 index 0000000000..595e71a733 --- /dev/null +++ b/rtkaio/Makefile @@ -0,0 +1,101 @@ +# Copyright (C) 2003, 2004, 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. + +# +# Sub-makefile for real-time kaio portion of the library. +# +subdir := rtkaio + +aio-routines := aio_cancel aio_error aio_fsync aio_misc aio_read \ + aio_read64 aio_return aio_suspend aio_write \ + aio_write64 lio_listio lio_listio64 aio_sigqueue \ + aio_notify +clock-routines := get_clockfreq clock_getcpuclockid \ + clock_getres clock_gettime clock_settime \ + clock_nanosleep +timer-routines := timer_create timer_delete timer_getoverr \ + timer_gettime timer_settime +shm-routines := shm_open shm_unlink +mq-routines := mq_open mq_close mq_unlink mq_getattr mq_setattr \ + mq_notify mq_send mq_receive mq_timedsend \ + mq_timedreceive + +librtkaio-routines = $(patsubst %,k%,$(aio-routines)) \ + $(patsubst %,kaio_%,$(clock-routines) $(timer-routines) \ + $(shm-routines) $(mq-routines)) + +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-aio7 tst-aio8 tst-aio9 tst-aio10 \ + tst-mqueue1 tst-mqueue2 tst-mqueue3 tst-mqueue4 \ + tst-mqueue5 tst-mqueue6 tst-mqueue7 tst-mqueue8 tst-mqueue9 \ + tst-timer3 tst-timer4 tst-timer5 \ + tst-cpuclock1 tst-cpuclock2 \ + tst-cputimer1 tst-cputimer2 tst-cputimer3 \ + tst-clock2 \ + tst-aiod tst-aiod64 tst-aiod2 tst-aiod3 tst-aiod4 tst-aiod5 + +extra-libs := librtkaio +extra-libs-others := $(extra-libs) + +include $(..)Makeconfig + +ifeq (yesyes,$(build-shared)$(elf)) +generated += librt.so$(librt.so-version) + +$(objpfx)librt.so$(librt.so-version): $(objpfx)librtkaio.so; $(make-link) +endif + +include $(..)Rules + +CFLAGS-kaio_suspend.c = -fexceptions +CFLAGS-kaio_clock_nanosleep.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-kaio_librt-cancellation.c = -fasynchronous-unwind-tables + +LDFLAGS-rtkaio.so = -Wl,-soname=lib$(libprefix)rt.so$(librt.so-version) \ + -Wl,--enable-new-dtags,-z,nodelete +CPPFLAGS-librtkaio += -DIS_IN_librt=1 -I$(..)rt + +rpath-dirs := $(patsubst rt,rtkaio,$(rpath-dirs)) + +ifeq (yesyes,$(build-shared)$(elf)) +others: $(objpfx)librt.so$(librt.so-version) +endif + +# Depend on libc.so so a DT_NEEDED is generated in the shared objects. +# This ensures they will load libc.so for needed symbols if loaded by +# a statically-linked program that hasn't already loaded it. +$(objpfx)librtkaio.so: $(common-objpfx)libc.so $(common-objpfx)libc_nonshared.a \ + $(shared-thread-library) \ + $(if $(filter yes,$(elf)), $(elfobjdir)/ld.so) + +ifeq (yes,$(build-shared)) +$(addprefix $(objpfx),$(tests)): $(objpfx)librtkaio.so $(shared-thread-library) +else +$(addprefix $(objpfx),$(tests)): $(objpfx)librtkaio.a $(static-thread-library) +endif +ifeq (yes,$(build-bounded)) +$(tests:%=$(objpfx)%-bp): $(objpfx)librtkaio_b.a $(bounded-thread-library) +endif + +tst-mqueue7-ARGS = -- $(built-program-cmd) + +ifeq (yes,$(build-static-nss)) +otherlibs += $(nssobjdir)/libnss_files.a $(resolvobjdir)/libnss_dns.a \ + $(resolvobjdir)/libresolv.a +endif diff --git a/rtkaio/Versions b/rtkaio/Versions new file mode 100644 index 0000000000..916fc68f13 --- /dev/null +++ b/rtkaio/Versions @@ -0,0 +1,25 @@ +librtkaio { + GLIBC_2.1 { + # AIO functions. + aio_cancel; aio_cancel64; aio_error; aio_error64; aio_fsync; aio_fsync64; + aio_init; aio_read; aio_read64; aio_return; aio_return64; aio_suspend; + aio_suspend64; aio_write; aio_write64; lio_listio; lio_listio64; + } + GLIBC_2.2 { + # c* + clock_getres; clock_gettime; clock_settime; clock_getcpuclockid; + clock_nanosleep; + + # s* + shm_open; shm_unlink; + + # t* + timer_create; timer_delete; timer_getoverrun; timer_gettime; + timer_settime; + } + GLIBC_2.3.4 { + # m* + mq_open; mq_close; mq_unlink; mq_getattr; mq_setattr; + mq_notify; mq_send; mq_receive; mq_timedsend; mq_timedreceive; + } +} diff --git a/rtkaio/Versions.def b/rtkaio/Versions.def new file mode 100644 index 0000000000..4213933661 --- /dev/null +++ b/rtkaio/Versions.def @@ -0,0 +1,8 @@ +librtkaio { + GLIBC_2.1 + GLIBC_2.2 + GLIBC_2.3 + GLIBC_2.3.3 + GLIBC_2.3.4 + GLIBC_2.4 +} diff --git a/rtkaio/configure b/rtkaio/configure new file mode 100644 index 0000000000..16ef6d957a --- /dev/null +++ b/rtkaio/configure @@ -0,0 +1,4 @@ +# This file is generated from configure.in by Autoconf. DO NOT EDIT! + +libc_add_on_canonical= +libc_add_on_subdirs=. diff --git a/rtkaio/configure.in b/rtkaio/configure.in new file mode 100644 index 0000000000..9e1b6a63c2 --- /dev/null +++ b/rtkaio/configure.in @@ -0,0 +1,5 @@ +dnl glibc configure fragment for rtkaio add-on +GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory. + +libc_add_on_canonical= +libc_add_on_subdirs=. diff --git a/rtkaio/kaio_cancel.c b/rtkaio/kaio_cancel.c new file mode 100644 index 0000000000..f1ea4b7ccd --- /dev/null +++ b/rtkaio/kaio_cancel.c @@ -0,0 +1 @@ +#include <aio_cancel.c> diff --git a/rtkaio/kaio_clock_getcpuclockid.c b/rtkaio/kaio_clock_getcpuclockid.c new file mode 100644 index 0000000000..ce738c0737 --- /dev/null +++ b/rtkaio/kaio_clock_getcpuclockid.c @@ -0,0 +1 @@ +#include <clock_getcpuclockid.c> diff --git a/rtkaio/kaio_clock_getres.c b/rtkaio/kaio_clock_getres.c new file mode 100644 index 0000000000..b902456fb4 --- /dev/null +++ b/rtkaio/kaio_clock_getres.c @@ -0,0 +1 @@ +#include <clock_getres.c> diff --git a/rtkaio/kaio_clock_gettime.c b/rtkaio/kaio_clock_gettime.c new file mode 100644 index 0000000000..2faa341bfb --- /dev/null +++ b/rtkaio/kaio_clock_gettime.c @@ -0,0 +1 @@ +#include <clock_gettime.c> diff --git a/rtkaio/kaio_clock_nanosleep.c b/rtkaio/kaio_clock_nanosleep.c new file mode 100644 index 0000000000..aed608bb0e --- /dev/null +++ b/rtkaio/kaio_clock_nanosleep.c @@ -0,0 +1 @@ +#include <clock_nanosleep.c> diff --git a/rtkaio/kaio_clock_settime.c b/rtkaio/kaio_clock_settime.c new file mode 100644 index 0000000000..7098fcacbf --- /dev/null +++ b/rtkaio/kaio_clock_settime.c @@ -0,0 +1 @@ +#include <clock_settime.c> diff --git a/rtkaio/kaio_error.c b/rtkaio/kaio_error.c new file mode 100644 index 0000000000..9fdf4f5f91 --- /dev/null +++ b/rtkaio/kaio_error.c @@ -0,0 +1 @@ +#include <aio_error.c> diff --git a/rtkaio/kaio_fsync.c b/rtkaio/kaio_fsync.c new file mode 100644 index 0000000000..f3483aef9e --- /dev/null +++ b/rtkaio/kaio_fsync.c @@ -0,0 +1 @@ +#include <aio_fsync.c> diff --git a/rtkaio/kaio_get_clockfreq.c b/rtkaio/kaio_get_clockfreq.c new file mode 100644 index 0000000000..cacab2ba2c --- /dev/null +++ b/rtkaio/kaio_get_clockfreq.c @@ -0,0 +1 @@ +#include <get_clockfreq.c> diff --git a/rtkaio/kaio_misc.c b/rtkaio/kaio_misc.c new file mode 100644 index 0000000000..16eaa21cf5 --- /dev/null +++ b/rtkaio/kaio_misc.c @@ -0,0 +1 @@ +#include <aio_misc.c> diff --git a/rtkaio/kaio_mq_close.c b/rtkaio/kaio_mq_close.c new file mode 100644 index 0000000000..ff6feda29b --- /dev/null +++ b/rtkaio/kaio_mq_close.c @@ -0,0 +1 @@ +#include <mq_close.c> diff --git a/rtkaio/kaio_mq_getattr.c b/rtkaio/kaio_mq_getattr.c new file mode 100644 index 0000000000..87c3d8e99f --- /dev/null +++ b/rtkaio/kaio_mq_getattr.c @@ -0,0 +1 @@ +#include <mq_getattr.c> diff --git a/rtkaio/kaio_mq_notify.c b/rtkaio/kaio_mq_notify.c new file mode 100644 index 0000000000..e464d407a8 --- /dev/null +++ b/rtkaio/kaio_mq_notify.c @@ -0,0 +1 @@ +#include <mq_notify.c> diff --git a/rtkaio/kaio_mq_open.c b/rtkaio/kaio_mq_open.c new file mode 100644 index 0000000000..54a3e489a0 --- /dev/null +++ b/rtkaio/kaio_mq_open.c @@ -0,0 +1 @@ +#include <mq_open.c> diff --git a/rtkaio/kaio_mq_receive.c b/rtkaio/kaio_mq_receive.c new file mode 100644 index 0000000000..38a663b5ca --- /dev/null +++ b/rtkaio/kaio_mq_receive.c @@ -0,0 +1 @@ +#include <mq_receive.c> diff --git a/rtkaio/kaio_mq_send.c b/rtkaio/kaio_mq_send.c new file mode 100644 index 0000000000..39b2325c4a --- /dev/null +++ b/rtkaio/kaio_mq_send.c @@ -0,0 +1 @@ +#include <mq_send.c> diff --git a/rtkaio/kaio_mq_setattr.c b/rtkaio/kaio_mq_setattr.c new file mode 100644 index 0000000000..44a1309422 --- /dev/null +++ b/rtkaio/kaio_mq_setattr.c @@ -0,0 +1 @@ +#include <mq_setattr.c> diff --git a/rtkaio/kaio_mq_timedreceive.c b/rtkaio/kaio_mq_timedreceive.c new file mode 100644 index 0000000000..6c0b727fb7 --- /dev/null +++ b/rtkaio/kaio_mq_timedreceive.c @@ -0,0 +1 @@ +#include <mq_timedreceive.c> diff --git a/rtkaio/kaio_mq_timedsend.c b/rtkaio/kaio_mq_timedsend.c new file mode 100644 index 0000000000..9923cb7e56 --- /dev/null +++ b/rtkaio/kaio_mq_timedsend.c @@ -0,0 +1 @@ +#include <mq_timedsend.c> diff --git a/rtkaio/kaio_mq_unlink.c b/rtkaio/kaio_mq_unlink.c new file mode 100644 index 0000000000..3cbf41155f --- /dev/null +++ b/rtkaio/kaio_mq_unlink.c @@ -0,0 +1 @@ +#include <mq_unlink.c> diff --git a/rtkaio/kaio_notify.c b/rtkaio/kaio_notify.c new file mode 100644 index 0000000000..6861e7fd78 --- /dev/null +++ b/rtkaio/kaio_notify.c @@ -0,0 +1 @@ +#include <aio_notify.c> diff --git a/rtkaio/kaio_read.c b/rtkaio/kaio_read.c new file mode 100644 index 0000000000..5d7774b818 --- /dev/null +++ b/rtkaio/kaio_read.c @@ -0,0 +1 @@ +#include <aio_read.c> diff --git a/rtkaio/kaio_read64.c b/rtkaio/kaio_read64.c new file mode 100644 index 0000000000..becd1bee8e --- /dev/null +++ b/rtkaio/kaio_read64.c @@ -0,0 +1 @@ +#include <aio_read64.c> diff --git a/rtkaio/kaio_return.c b/rtkaio/kaio_return.c new file mode 100644 index 0000000000..8f1d2c9997 --- /dev/null +++ b/rtkaio/kaio_return.c @@ -0,0 +1 @@ +#include <aio_return.c> diff --git a/rtkaio/kaio_shm_open.c b/rtkaio/kaio_shm_open.c new file mode 100644 index 0000000000..f596e41084 --- /dev/null +++ b/rtkaio/kaio_shm_open.c @@ -0,0 +1 @@ +#include <shm_open.c> diff --git a/rtkaio/kaio_shm_unlink.c b/rtkaio/kaio_shm_unlink.c new file mode 100644 index 0000000000..dd725afe32 --- /dev/null +++ b/rtkaio/kaio_shm_unlink.c @@ -0,0 +1 @@ +#include <shm_unlink.c> diff --git a/rtkaio/kaio_sigqueue.c b/rtkaio/kaio_sigqueue.c new file mode 100644 index 0000000000..6e49f01d61 --- /dev/null +++ b/rtkaio/kaio_sigqueue.c @@ -0,0 +1 @@ +#include <aio_sigqueue.c> diff --git a/rtkaio/kaio_suspend.c b/rtkaio/kaio_suspend.c new file mode 100644 index 0000000000..145420bd12 --- /dev/null +++ b/rtkaio/kaio_suspend.c @@ -0,0 +1 @@ +#include <aio_suspend.c> diff --git a/rtkaio/kaio_timer_create.c b/rtkaio/kaio_timer_create.c new file mode 100644 index 0000000000..47463959aa --- /dev/null +++ b/rtkaio/kaio_timer_create.c @@ -0,0 +1 @@ +#include <timer_create.c> diff --git a/rtkaio/kaio_timer_delete.c b/rtkaio/kaio_timer_delete.c new file mode 100644 index 0000000000..d5c94537d6 --- /dev/null +++ b/rtkaio/kaio_timer_delete.c @@ -0,0 +1 @@ +#include <timer_delete.c> diff --git a/rtkaio/kaio_timer_getoverr.c b/rtkaio/kaio_timer_getoverr.c new file mode 100644 index 0000000000..8f1eca4996 --- /dev/null +++ b/rtkaio/kaio_timer_getoverr.c @@ -0,0 +1 @@ +#include <timer_getoverr.c> diff --git a/rtkaio/kaio_timer_gettime.c b/rtkaio/kaio_timer_gettime.c new file mode 100644 index 0000000000..cf592f89ed --- /dev/null +++ b/rtkaio/kaio_timer_gettime.c @@ -0,0 +1 @@ +#include <timer_gettime.c> diff --git a/rtkaio/kaio_timer_settime.c b/rtkaio/kaio_timer_settime.c new file mode 100644 index 0000000000..2a7c789e64 --- /dev/null +++ b/rtkaio/kaio_timer_settime.c @@ -0,0 +1 @@ +#include <timer_settime.c> diff --git a/rtkaio/kaio_write.c b/rtkaio/kaio_write.c new file mode 100644 index 0000000000..68e47ca1f3 --- /dev/null +++ b/rtkaio/kaio_write.c @@ -0,0 +1 @@ +#include <aio_write.c> diff --git a/rtkaio/kaio_write64.c b/rtkaio/kaio_write64.c new file mode 100644 index 0000000000..316e55dcf3 --- /dev/null +++ b/rtkaio/kaio_write64.c @@ -0,0 +1 @@ +#include <aio_write64.c> diff --git a/rtkaio/klio_listio.c b/rtkaio/klio_listio.c new file mode 100644 index 0000000000..08378bd22d --- /dev/null +++ b/rtkaio/klio_listio.c @@ -0,0 +1 @@ +#include <lio_listio.c> diff --git a/rtkaio/klio_listio64.c b/rtkaio/klio_listio64.c new file mode 100644 index 0000000000..3a087e41b1 --- /dev/null +++ b/rtkaio/klio_listio64.c @@ -0,0 +1 @@ +#include <lio_listio64.c> diff --git a/rtkaio/shlib-versions b/rtkaio/shlib-versions new file mode 100644 index 0000000000..97c78f50aa --- /dev/null +++ b/rtkaio/shlib-versions @@ -0,0 +1,2 @@ +mips.*-.*-linux.* librtkaio=1 GLIBC_2.0 GLIBC_2.2 +.*-.*-.* librtkaio=1 diff --git a/rtkaio/sysdeps/pthread/Makefile b/rtkaio/sysdeps/pthread/Makefile new file mode 100644 index 0000000000..7ced3eb5a9 --- /dev/null +++ b/rtkaio/sysdeps/pthread/Makefile @@ -0,0 +1,39 @@ +ifeq ($(filter nptl,$(sorted-subdirs)),nptl) + +ifeq ($(subdir),rtkaio) +librtkaio-sysdep_routines += kaio_timer_routines librtkaio-cancellation rtkaio-unwind-resume +librtkaio-shared-only-routines += rtkaio-unwind-resume +tests += tst-cancel17 tst-cancelx17 +CPPFLAGS-kaio_timer_routines.c = -I../nptl +CFLAGS-librtkaio-cancellation.c += -fexceptions -fasynchronous-unwind-tables +CFLAGS-rtkaio-unwind-resume.c += -fexceptions -fasynchronous-unwind-tables +CFLAGS-tst-cancelx17.c += -fexceptions + +ifeq (yes,$(build-shared)) +$(objpfx)tst-timer: $(objpfx)librtkaio.so $(shared-thread-library) +else +$(objpfx)tst-timer: $(objpfx)librtkaio.a $(static-thread-library) +endif + +ifeq ($(have-forced-unwind),yes) +tests += tst-mqueue8x +CFLAGS-tst-mqueue8x.c += -fexceptions +endif +endif + +endif + +ifeq ($(filter linuxthreads,$(sorted-subdirs)),linuxthreads) + +ifeq ($(subdir),rtkaio) +librtkaio-sysdep_routines += kaio_timer_routines +CPPFLAGS += -DBROKEN_THREAD_SIGNALS + +ifeq (yes,$(build-shared)) +$(objpfx)tst-timer: $(objpfx)librtkaio.so $(shared-thread-library) +else +$(objpfx)tst-timer: $(objpfx)librtkaio.a $(static-thread-library) +endif +endif + +endif diff --git a/rtkaio/sysdeps/pthread/Versions b/rtkaio/sysdeps/pthread/Versions new file mode 100644 index 0000000000..7677b76687 --- /dev/null +++ b/rtkaio/sysdeps/pthread/Versions @@ -0,0 +1,7 @@ +%ifdef HAVE_FORCED_UNWIND +librtkaio { + GLIBC_2.4 { + lio_listio; lio_listio64; + } +} +%endif diff --git a/rtkaio/sysdeps/pthread/kaio_timer_routines.c b/rtkaio/sysdeps/pthread/kaio_timer_routines.c new file mode 100644 index 0000000000..3aa70ede12 --- /dev/null +++ b/rtkaio/sysdeps/pthread/kaio_timer_routines.c @@ -0,0 +1 @@ +#include <timer_routines.c> diff --git a/rtkaio/sysdeps/pthread/librtkaio-cancellation.c b/rtkaio/sysdeps/pthread/librtkaio-cancellation.c new file mode 100644 index 0000000000..77c0870e32 --- /dev/null +++ b/rtkaio/sysdeps/pthread/librtkaio-cancellation.c @@ -0,0 +1 @@ +#include <librt-cancellation.c> diff --git a/rtkaio/sysdeps/pthread/rtkaio-unwind-resume.c b/rtkaio/sysdeps/pthread/rtkaio-unwind-resume.c new file mode 100644 index 0000000000..09499a51a9 --- /dev/null +++ b/rtkaio/sysdeps/pthread/rtkaio-unwind-resume.c @@ -0,0 +1 @@ +#include <rt-unwind-resume.c> diff --git a/rtkaio/sysdeps/pthread/tst-cancel17.c b/rtkaio/sysdeps/pthread/tst-cancel17.c new file mode 100644 index 0000000000..3a7e7ef1ab --- /dev/null +++ b/rtkaio/sysdeps/pthread/tst-cancel17.c @@ -0,0 +1 @@ +#include <nptl/tst-cancel17.c> diff --git a/rtkaio/sysdeps/pthread/tst-cancelx17.c b/rtkaio/sysdeps/pthread/tst-cancelx17.c new file mode 100644 index 0000000000..c6c833b60c --- /dev/null +++ b/rtkaio/sysdeps/pthread/tst-cancelx17.c @@ -0,0 +1 @@ +#include "tst-cancel17.c" diff --git a/rtkaio/sysdeps/pthread/tst-mqueue8x.c b/rtkaio/sysdeps/pthread/tst-mqueue8x.c new file mode 100644 index 0000000000..1259ebdf50 --- /dev/null +++ b/rtkaio/sysdeps/pthread/tst-mqueue8x.c @@ -0,0 +1 @@ +#include_next <tst-mqueue8x.c> diff --git a/rtkaio/sysdeps/pthread/tst-timer.c b/rtkaio/sysdeps/pthread/tst-timer.c new file mode 100644 index 0000000000..9f38f9b2da --- /dev/null +++ b/rtkaio/sysdeps/pthread/tst-timer.c @@ -0,0 +1 @@ +#include_next <tst-timer.c> diff --git a/rtkaio/sysdeps/unix/alpha/Makefile b/rtkaio/sysdeps/unix/alpha/Makefile new file mode 100644 index 0000000000..223ec37222 --- /dev/null +++ b/rtkaio/sysdeps/unix/alpha/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),rtkaio) +librtkaio-sysdep_routines += rtkaio-sysdep +endif diff --git a/rtkaio/sysdeps/unix/alpha/rtkaio-sysdep.S b/rtkaio/sysdeps/unix/alpha/rtkaio-sysdep.S new file mode 100644 index 0000000000..11ee214b23 --- /dev/null +++ b/rtkaio/sysdeps/unix/alpha/rtkaio-sysdep.S @@ -0,0 +1 @@ +#include <rt-sysdep.S> diff --git a/rtkaio/sysdeps/unix/sysv/linux/Implies b/rtkaio/sysdeps/unix/sysv/linux/Implies new file mode 100644 index 0000000000..329b6a20ca --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/Implies @@ -0,0 +1 @@ +rtkaio diff --git a/rtkaio/sysdeps/unix/sysv/linux/Makefile b/rtkaio/sysdeps/unix/sysv/linux/Makefile new file mode 100644 index 0000000000..9ed3d7551a --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/Makefile @@ -0,0 +1,4 @@ +ifeq ($(subdir),rtkaio) +CFLAGS-kaio_mq_send.c += -fexceptions +CFLAGS-kaio_mq_receive.c += -fexceptions +endif diff --git a/rtkaio/sysdeps/unix/sysv/linux/alpha/Versions b/rtkaio/sysdeps/unix/sysv/linux/alpha/Versions new file mode 100644 index 0000000000..b2d59a9140 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/alpha/Versions @@ -0,0 +1,6 @@ +librtkaio { + GLIBC_2.3 { + # AIO functions. + aio_cancel; aio_cancel64; + } +} diff --git a/rtkaio/sysdeps/unix/sysv/linux/alpha/kaio_cancel.c b/rtkaio/sysdeps/unix/sysv/linux/alpha/kaio_cancel.c new file mode 100644 index 0000000000..6e345e1643 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/alpha/kaio_cancel.c @@ -0,0 +1,33 @@ +#include <shlib-compat.h> + +#define aio_cancel64 XXX +#include <aio.h> +#undef aio_cancel64 +#include <errno.h> + +extern __typeof (aio_cancel) __new_aio_cancel; +extern __typeof (aio_cancel) __old_aio_cancel; + +#define aio_cancel __new_aio_cancel + +#include <sysdeps/unix/sysv/linux/kaio_cancel.c> + +#undef aio_cancel +strong_alias (__new_aio_cancel, __new_aio_cancel64); +versioned_symbol (librt, __new_aio_cancel, aio_cancel, GLIBC_2_3); +versioned_symbol (librt, __new_aio_cancel64, aio_cancel64, GLIBC_2_3); + +#if SHLIB_COMPAT (librt, GLIBC_2_1, GLIBC_2_3) + +#undef ECANCELED +#define aio_cancel __old_aio_cancel +#define ECANCELED 125 + +#include <sysdeps/unix/sysv/linux/kaio_cancel.c> + +#undef aio_cancel +strong_alias (__old_aio_cancel, __old_aio_cancel64); +compat_symbol (librt, __old_aio_cancel, aio_cancel, GLIBC_2_1); +compat_symbol (librt, __old_aio_cancel64, aio_cancel64, GLIBC_2_1); + +#endif diff --git a/rtkaio/sysdeps/unix/sysv/linux/ia64/Makefile b/rtkaio/sysdeps/unix/sysv/linux/ia64/Makefile new file mode 100644 index 0000000000..ead21fb111 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/ia64/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),rtkaio) +librtkaio-routines += rtkaio-sysdep +endif diff --git a/rtkaio/sysdeps/unix/sysv/linux/ia64/Versions b/rtkaio/sysdeps/unix/sysv/linux/ia64/Versions new file mode 100644 index 0000000000..7443c81d6a --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/ia64/Versions @@ -0,0 +1,9 @@ +%ifdef HAVE_FORCED_UNWIND +librtkaio { + GLIBC_2.3.3 { + # Changed timer_t. + timer_create; timer_delete; timer_getoverrun; timer_gettime; + timer_settime; + } +} +%endif diff --git a/rtkaio/sysdeps/unix/sysv/linux/ia64/rtkaio-sysdep.S b/rtkaio/sysdeps/unix/sysv/linux/ia64/rtkaio-sysdep.S new file mode 100644 index 0000000000..11ee214b23 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/ia64/rtkaio-sysdep.S @@ -0,0 +1 @@ +#include <rt-sysdep.S> diff --git a/rtkaio/sysdeps/unix/sysv/linux/kaio_cancel.c b/rtkaio/sysdeps/unix/sysv/linux/kaio_cancel.c new file mode 100644 index 0000000000..7d2738d5bc --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/kaio_cancel.c @@ -0,0 +1,238 @@ +/* Cancel requests associated with given file descriptor. + Copyright (C) 1997, 1998, 2000, 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. + + 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 use an UGLY hack to prevent gcc from finding us cheating. The + implementation of aio_cancel and aio_cancel64 are identical and so + we want to avoid code duplication by using aliases. But gcc sees + the different parameter lists and prints a warning. We define here + a function so that aio_cancel64 has no prototype. */ +#ifndef aio_cancel +#define aio_cancel64 XXX +#include <aio.h> +/* And undo the hack. */ +#undef aio_cancel64 +#endif + +#include <kaio_misc.h> + +#ifndef USE_KAIO +#include <aio_cancel.c> +#else + +#include <assert.h> +#include <errno.h> + +int +aio_cancel (fildes, aiocbp) + int fildes; + struct aiocb *aiocbp; +{ + struct requestlist *req = NULL; + int result = AIO_ALLDONE; + + /* If fildes is invalid, error. */ + if (fcntl (fildes, F_GETFL) < 0) + { + __set_errno (EBADF); + return -1; + } + + /* Request the mutex. */ + pthread_mutex_lock (&__aio_requests_mutex); + + /* We are asked to cancel a specific AIO request. */ + if (aiocbp != NULL) + { + /* If the AIO request is not for this descriptor it has no value + to look for the request block. */ + if (aiocbp->aio_fildes != fildes) + { + pthread_mutex_unlock (&__aio_requests_mutex); + __set_errno (EINVAL); + return -1; + } + else if (aiocbp->__error_code == EINPROGRESS) + { + struct requestlist *last = NULL; + + req = __aio_find_req_fd (fildes); + + if (req != NULL) + while (req->aiocbp != (aiocb_union *) aiocbp) + { + last = req; + req = req->next_prio; + if (req == NULL) + break; + } + + if (req != NULL) + { + /* Don't remove the entry if a thread is already working on + it. */ + if (req->running == allocated) + { + result = AIO_NOTCANCELED; + req = NULL; + } + else + { + /* We can remove the entry. */ + __aio_remove_request (last, req, 0); + + result = AIO_CANCELED; + + req->next_prio = NULL; + } + } + else + { + /* Try kernel requests. */ + req = __aio_find_req ((aiocb_union *) aiocbp); + + if (req == NULL) + { + pthread_mutex_unlock (&__aio_requests_mutex); + __set_errno (EINVAL); + return -1; + } + + assert (req->kioctx != KCTX_NONE); + + /* If kernel is working on it, try cancelling it. */ + if (req->running == allocated) + { + struct kio_event ev; + INTERNAL_SYSCALL_DECL (err); + int res; + + res = INTERNAL_SYSCALL (io_cancel, err, 3, __aio_kioctx, + &req->kiocb, &ev); + if (INTERNAL_SYSCALL_ERROR_P (res, err)) + { + result = AIO_NOTCANCELED; + req = NULL; + } + else + req->running = queued; + } + if (req != NULL) + { + /* We can remove the entry. */ + __aio_remove_krequest (req); + result = AIO_CANCELED; + req->next_prio = NULL; + } + } + } + } + else + { + /* Find the beginning of the list of all requests for this + desriptor. */ + req = __aio_find_req_fd (fildes); + + /* If any request is worked on by a thread it must be the first. + So either we can delete all requests or all but the first. */ + if (req != NULL) + { + if (req->running == allocated) + { + struct requestlist *old = req; + req = req->next_prio; + old->next_prio = NULL; + + result = AIO_NOTCANCELED; + + if (req != NULL) + __aio_remove_request (old, req, 1); + } + else + { + result = AIO_CANCELED; + + /* We can remove the entry. */ + __aio_remove_request (NULL, req, 1); + } + } + + if (result != AIO_NOTCANCELED) + { + /* Try to cancel kernel requests. */ + struct requestlist *kreq = __aio_find_kreq_fd (fildes); + + while (kreq) + { + struct requestlist *next; + + /* If kernel is working on it, try cancelling it. */ + if (kreq->running == allocated) + { + struct kio_event ev; + INTERNAL_SYSCALL_DECL (err); + int res; + + res = INTERNAL_SYSCALL (io_cancel, err, 3, __aio_kioctx, + &kreq->kiocb, &ev); + if (INTERNAL_SYSCALL_ERROR_P (res, err)) + { + result = AIO_NOTCANCELED; + break; + } + else + kreq->running = queued; + } + next = kreq->next_prio; + __aio_remove_krequest (kreq); + result = AIO_CANCELED; + kreq->next_prio = NULL; + assert (kreq->running == yes || kreq->running == queued); + kreq->aiocbp->aiocb.__error_code = ECANCELED; + kreq->aiocbp->aiocb.__return_value = -1; + __aio_notify (kreq); + __aio_free_request (kreq); + kreq = next; + } + } + } + + /* Mark requests as canceled and send signal. */ + while (req != NULL) + { + struct requestlist *old = req; + assert (req->running == yes || req->running == queued); + req->aiocbp->aiocb.__error_code = ECANCELED; + req->aiocbp->aiocb.__return_value = -1; + __aio_notify (req); + req = req->next_prio; + __aio_free_request (old); + } + + /* Release the mutex. */ + pthread_mutex_unlock (&__aio_requests_mutex); + + return result; +} + +#ifndef aio_cancel +weak_alias (aio_cancel, aio_cancel64) +#endif + +#endif diff --git a/rtkaio/sysdeps/unix/sysv/linux/kaio_error.c b/rtkaio/sysdeps/unix/sysv/linux/kaio_error.c new file mode 100644 index 0000000000..23859c363a --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/kaio_error.c @@ -0,0 +1,54 @@ +/* Return error status of asynchronous I/O request. + Copyright (C) 1997, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. + + 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 use an UGLY hack to prevent gcc from finding us cheating. The + implementation of aio_error and aio_error64 are identical and so + we want to avoid code duplication by using aliases. But gcc sees + the different parameter lists and prints a warning. We define here + a function so that aio_error64 has no prototype. */ +#define aio_error64 XXX +#include <aio.h> +/* And undo the hack. */ +#undef aio_error64 + +#include <kaio_misc.h> + +#ifndef USE_KAIO +#include <aio_error.c> +#else + +#include <errno.h> + +int +aio_error (aiocbp) + const struct aiocb *aiocbp; +{ + int ret = aiocbp->__error_code; + + if (ret == EINPROGRESS) + { + __aio_read_one_event (); + ret = aiocbp->__error_code; + } + return ret; +} + +weak_alias (aio_error, aio_error64) +#endif diff --git a/rtkaio/sysdeps/unix/sysv/linux/kaio_fsync.c b/rtkaio/sysdeps/unix/sysv/linux/kaio_fsync.c new file mode 100644 index 0000000000..d51bbe0135 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/kaio_fsync.c @@ -0,0 +1,6 @@ +#define aio_fsync64 XXX +#include <aio.h> +/* And undo the hack. */ +#undef aio_fsync64 +#include <kaio_misc.h> +#include <aio_fsync.c> diff --git a/rtkaio/sysdeps/unix/sysv/linux/kaio_misc.c b/rtkaio/sysdeps/unix/sysv/linux/kaio_misc.c new file mode 100644 index 0000000000..76e0c430b7 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/kaio_misc.c @@ -0,0 +1,1130 @@ +/* Handle general operations. + Copyright (C) 1997,1998,1999,2000,2001,2002,2003,2006 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. + + 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. */ + +#include <kaio_misc.h> + +#ifndef USE_KAIO +#include <aio_misc.c> +#else + +#include <aio.h> +#include <assert.h> +#include <atomic.h> +#include <errno.h> +#include <limits.h> +#include <pthread.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/sysmacros.h> + +#ifndef aio_create_helper_thread +# define aio_create_helper_thread __aio_create_helper_thread + +extern inline int +__aio_create_helper_thread (pthread_t *threadp, void *(*tf) (void *), void *arg) +{ + pthread_attr_t attr; + + /* Make sure the thread is created detached. */ + pthread_attr_init (&attr); + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + + int ret = pthread_create (threadp, &attr, tf, arg); + + (void) pthread_attr_destroy (&attr); + return ret; +} + +#endif + + +static void add_request_to_runlist (struct requestlist *newrequest) + internal_function; +static int add_request_to_list (struct requestlist *newrequest, int fildes, + int prio) + internal_function; +static void * handle_kernel_aio (void *arg); +static void kernel_callback (kctx_t ctx, struct kiocb *kiocb, long res, + long res2); + +/* Pool of request list entries. */ +static struct requestlist **pool; + +/* Number of total and allocated pool entries. */ +static size_t pool_max_size; +static size_t pool_size; + +/* Kernel AIO context. */ +kctx_t __aio_kioctx = KCTX_NONE; +int __have_no_kernel_aio; +int __kernel_thread_started; + +/* We implement a two dimensional array but allocate each row separately. + The macro below determines how many entries should be used per row. + It should better be a power of two. */ +#define ENTRIES_PER_ROW 32 + +/* How many rows we allocate at once. */ +#define ROWS_STEP 8 + +/* List of available entries. */ +static struct requestlist *freelist; + +/* List of request waiting to be processed. */ +static struct requestlist *runlist; + +/* Structure list of all currently processed requests. */ +static struct requestlist *requests, *krequests; + +/* Number of threads currently running. */ +static int nthreads; + +/* Number of threads waiting for work to arrive. */ +static int idle_thread_count; + + +/* These are the values used to optimize the use of AIO. The user can + overwrite them by using the `aio_init' function. */ +static struct aioinit optim = +{ + 20, /* int aio_threads; Maximal number of threads. */ + 64, /* int aio_num; Number of expected simultanious requests. */ + 0, + 0, + 0, + 0, + 1, + 0 +}; + + +/* Since the list is global we need a mutex protecting it. */ +pthread_mutex_t __aio_requests_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; + +/* When you add a request to the list and there are idle threads present, + you signal this condition variable. When a thread finishes work, it waits + on this condition variable for a time before it actually exits. */ +pthread_cond_t __aio_new_request_notification = PTHREAD_COND_INITIALIZER; + + +/* Functions to handle request list pool. */ +static struct requestlist * +get_elem (void) +{ + struct requestlist *result; + + if (freelist == NULL) + { + struct requestlist *new_row; + int cnt; + + assert (sizeof (struct aiocb) == sizeof (struct aiocb64)); + + if (pool_size + 1 >= pool_max_size) + { + size_t new_max_size = pool_max_size + ROWS_STEP; + struct requestlist **new_tab; + + new_tab = (struct requestlist **) + realloc (pool, new_max_size * sizeof (struct requestlist *)); + + if (new_tab == NULL) + return NULL; + + pool_max_size = new_max_size; + pool = new_tab; + } + + /* Allocate the new row. */ + cnt = pool_size == 0 ? optim.aio_num : ENTRIES_PER_ROW; + new_row = (struct requestlist *) calloc (cnt, + sizeof (struct requestlist)); + if (new_row == NULL) + return NULL; + + pool[pool_size++] = new_row; + + /* Put all the new entries in the freelist. */ + do + { + new_row->next_prio = freelist; + freelist = new_row++; + } + while (--cnt > 0); + } + + result = freelist; + freelist = freelist->next_prio; + + return result; +} + + +void +internal_function +__aio_free_request (struct requestlist *elem) +{ + elem->running = no; + elem->next_prio = freelist; + freelist = elem; +} + + +struct requestlist * +internal_function +__aio_find_req (aiocb_union *elem) +{ + struct requestlist *runp; + int fildes = elem->aiocb.aio_fildes; + int i; + + for (i = 0; i < 2; i++) + { + runp = i ? requests : krequests; + + while (runp != NULL && runp->aiocbp->aiocb.aio_fildes < fildes) + runp = runp->next_fd; + + if (runp != NULL) + { + if (runp->aiocbp->aiocb.aio_fildes != fildes) + runp = NULL; + else + while (runp != NULL && runp->aiocbp != elem) + runp = runp->next_prio; + if (runp != NULL) + return runp; + } + } + + return NULL; +} + + +struct requestlist * +internal_function +__aio_find_req_fd (int fildes) +{ + struct requestlist *runp = requests; + + while (runp != NULL && runp->aiocbp->aiocb.aio_fildes < fildes) + runp = runp->next_fd; + + return (runp != NULL && runp->aiocbp->aiocb.aio_fildes == fildes + ? runp : NULL); +} + + +struct requestlist * +internal_function +__aio_find_kreq_fd (int fildes) +{ + struct requestlist *runp = krequests; + + while (runp != NULL && runp->aiocbp->aiocb.aio_fildes < fildes) + runp = runp->next_fd; + + return (runp != NULL && runp->aiocbp->aiocb.aio_fildes == fildes + ? runp : NULL); +} + + +void +internal_function +__aio_remove_request (struct requestlist *last, struct requestlist *req, + int all) +{ + assert (req->running == yes || req->running == queued + || req->running == done); + assert (req->kioctx == KCTX_NONE); + + if (last != NULL) + last->next_prio = all ? NULL : req->next_prio; + else + { + if (all || req->next_prio == NULL) + { + if (req->last_fd != NULL) + req->last_fd->next_fd = req->next_fd; + else + requests = req->next_fd; + if (req->next_fd != NULL) + req->next_fd->last_fd = req->last_fd; + } + else + { + if (req->last_fd != NULL) + req->last_fd->next_fd = req->next_prio; + else + requests = req->next_prio; + + if (req->next_fd != NULL) + req->next_fd->last_fd = req->next_prio; + + req->next_prio->last_fd = req->last_fd; + req->next_prio->next_fd = req->next_fd; + + /* Mark this entry as runnable. */ + req->next_prio->running = yes; + } + + if (req->running == yes) + { + struct requestlist *runp = runlist; + + last = NULL; + while (runp != NULL) + { + if (runp == req) + { + if (last == NULL) + runlist = runp->next_run; + else + last->next_run = runp->next_run; + break; + } + last = runp; + runp = runp->next_run; + } + } + } +} + +void +internal_function +__aio_remove_krequest (struct requestlist *req) +{ + assert (req->running == yes || req->running == queued + || req->running == done); + assert (req->kioctx != KCTX_NONE); + + if (req->prev_prio != NULL) + { + req->prev_prio->next_prio = req->next_prio; + if (req->next_prio != NULL) + req->next_prio->prev_prio = req->prev_prio; + } + else if (req->next_prio == NULL) + { + if (req->last_fd != NULL) + req->last_fd->next_fd = req->next_fd; + else + krequests = req->next_fd; + if (req->next_fd != NULL) + req->next_fd->last_fd = req->last_fd; + } + else + { + if (req->last_fd != NULL) + req->last_fd->next_fd = req->next_prio; + else + krequests = req->next_prio; + if (req->next_fd != NULL) + req->next_fd->last_fd = req->next_prio; + + req->next_prio->prev_prio = NULL; + req->next_prio->last_fd = req->last_fd; + req->next_prio->next_fd = req->next_fd; + } +} + + +/* The thread handler. */ +static void *handle_fildes_io (void *arg); +static int wait_for_kernel_requests (int fildes); + + +/* User optimization. */ +void +__aio_init (const struct aioinit *init) +{ + /* Get the mutex. */ + pthread_mutex_lock (&__aio_requests_mutex); + + /* Only allow writing new values if the table is not yet allocated. */ + if (pool == NULL) + { + optim.aio_threads = init->aio_threads < 1 ? 1 : init->aio_threads; + optim.aio_num = (init->aio_num < ENTRIES_PER_ROW + ? ENTRIES_PER_ROW + : init->aio_num & ~ENTRIES_PER_ROW); + } + + if (init->aio_idle_time != 0) + optim.aio_idle_time = init->aio_idle_time; + + /* Release the mutex. */ + pthread_mutex_unlock (&__aio_requests_mutex); +} +weak_alias (__aio_init, aio_init) + +static void +kernel_callback (kctx_t ctx, struct kiocb *kiocb, long res, long res2) +{ + struct requestlist *req = (struct requestlist *)kiocb; + long errcode = 0; + + if (res < 0 && res > -1000) + { + errcode = -res; + res = -1; + } + req->aiocbp->aiocb.__return_value = res; + atomic_write_barrier (); + req->aiocbp->aiocb.__error_code = errcode; + __aio_notify (req); + assert (req->running == allocated); + req->running = done; + __aio_remove_krequest (req); + __aio_free_request (req); +} + +void +internal_function +__aio_read_one_event (void) +{ + struct kio_event ev[10]; + struct timespec ts; + int count, i; + + if (__aio_kioctx == KCTX_NONE) + return; + ts.tv_sec = 0; + ts.tv_nsec = 0; + do + { + INTERNAL_SYSCALL_DECL (err); + count = INTERNAL_SYSCALL (io_getevents, err, 5, __aio_kioctx, 0, 10, + ev, &ts); + if (INTERNAL_SYSCALL_ERROR_P (count, err) || count == 0) + break; + pthread_mutex_lock (&__aio_requests_mutex); + for (i = 0; i < count; i++) + { + void (*cb)(kctx_t, struct kiocb *, long, long); + + cb = (void *) (uintptr_t) ev[i].kioe_data; + cb (__aio_kioctx, (struct kiocb *) (uintptr_t) ev[i].kioe_obj, + ev[i].kioe_res, ev[i].kioe_res2); + } + pthread_mutex_unlock (&__aio_requests_mutex); + } + while (count == 10); +} + +int +internal_function +__aio_wait_for_events (kctx_t kctx, const struct timespec *timespec) +{ + int ret, i; + struct kio_event ev[10]; + struct timespec ts; + INTERNAL_SYSCALL_DECL (err); + + pthread_mutex_unlock (&__aio_requests_mutex); + ts.tv_sec = 0; + ts.tv_nsec = 0; + do + { + ret = INTERNAL_SYSCALL (io_getevents, err, 5, kctx, 1, 10, ev, + timespec); + if (INTERNAL_SYSCALL_ERROR_P (ret, err) || ret == 0) + break; + + pthread_mutex_lock (&__aio_requests_mutex); + for (i = 0; i < ret; i++) + { + void (*cb)(kctx_t, struct kiocb *, long, long); + + cb = (void *) (uintptr_t) ev[i].kioe_data; + cb (kctx, (struct kiocb *) (uintptr_t) ev[i].kioe_obj, + ev[i].kioe_res, ev[i].kioe_res2); + } + if (ret < 10) + return 0; + pthread_mutex_unlock (&__aio_requests_mutex); + timespec = &ts; + } + while (1); + + pthread_mutex_lock (&__aio_requests_mutex); + return (timespec != &ts + && INTERNAL_SYSCALL_ERROR_P (ret, err) + && INTERNAL_SYSCALL_ERRNO (ret, err) == ETIMEDOUT) ? ETIMEDOUT : 0; +} + +int +internal_function +__aio_create_kernel_thread (void) +{ + pthread_t thid; + + if (__kernel_thread_started) + return 0; + + if (aio_create_helper_thread (&thid, handle_kernel_aio, NULL) != 0) + return -1; + __kernel_thread_started = 1; + return 0; +} + +static void * +handle_kernel_aio (void *arg __attribute__((unused))) +{ + int ret, i; + INTERNAL_SYSCALL_DECL (err); + struct kio_event ev[10]; + + for (;;) + { + ret = INTERNAL_SYSCALL (io_getevents, err, 5, __aio_kioctx, 1, 10, ev, + NULL); + if (INTERNAL_SYSCALL_ERROR_P (ret, err) || ret == 0) + continue; + pthread_mutex_lock (&__aio_requests_mutex); + for (i = 0; i < ret; i++) + { + void (*cb)(kctx_t, struct kiocb *, long, long); + + cb = (void *) (uintptr_t) ev[i].kioe_data; + cb (__aio_kioctx, (struct kiocb *) (uintptr_t) ev[i].kioe_obj, + ev[i].kioe_res, ev[i].kioe_res2); + } + pthread_mutex_unlock (&__aio_requests_mutex); + } + return NULL; +} + +static int +internal_function +add_request_to_list (struct requestlist *newp, int fildes, int prio) +{ + struct requestlist *last, *runp, *reqs; + + last = NULL; + reqs = newp->kioctx != KCTX_NONE ? krequests : requests; + runp = reqs; + + /* First look whether the current file descriptor is currently + worked with. */ + while (runp != NULL + && runp->aiocbp->aiocb.aio_fildes < fildes) + { + last = runp; + runp = runp->next_fd; + } + + if (runp != NULL + && runp->aiocbp->aiocb.aio_fildes == fildes) + { + /* The current file descriptor is worked on. It makes no sense + to start another thread since this new thread would fight + with the running thread for the resources. But we also cannot + say that the thread processing this desriptor shall immediately + after finishing the current job process this request if there + are other threads in the running queue which have a higher + priority. */ + + /* Simply enqueue it after the running one according to the + priority. */ + while (runp->next_prio != NULL + && runp->next_prio->aiocbp->aiocb.__abs_prio >= prio) + runp = runp->next_prio; + + newp->next_prio = runp->next_prio; + runp->next_prio = newp; + if (newp->kioctx != KCTX_NONE) + { + newp->prev_prio = runp; + if (newp->next_prio != NULL) + newp->next_prio->prev_prio = newp; + } + return queued; + } + else + { + /* Enqueue this request for a new descriptor. */ + if (last == NULL) + { + newp->last_fd = NULL; + newp->next_fd = reqs; + if (reqs != NULL) + reqs->last_fd = newp; + if (newp->kioctx != KCTX_NONE) + krequests = newp; + else + requests = newp; + } + else + { + newp->next_fd = last->next_fd; + newp->last_fd = last; + last->next_fd = newp; + if (newp->next_fd != NULL) + newp->next_fd->last_fd = newp; + } + + newp->next_prio = NULL; + if (newp->kioctx != KCTX_NONE) + newp->prev_prio = NULL; + return yes; + } +} + +static int +internal_function +__aio_enqueue_user_request (struct requestlist *newp) +{ + int result = 0; + int running = add_request_to_list (newp, newp->aiocbp->aiocb.aio_fildes, + newp->aiocbp->aiocb.__abs_prio); + + if (running == yes) + { + /* We try to create a new thread for this file descriptor. The + function which gets called will handle all available requests + for this descriptor and when all are processed it will + terminate. + + If no new thread can be created or if the specified limit of + threads for AIO is reached we queue the request. */ + + /* See if we need to and are able to create a thread. */ + if (nthreads < optim.aio_threads && idle_thread_count == 0) + { + pthread_t thid; + + running = newp->running = allocated; + + /* Now try to start a thread. */ + if (aio_create_helper_thread (&thid, handle_fildes_io, newp) == 0) + /* We managed to enqueue the request. All errors which can + happen now can be recognized by calls to `aio_return' and + `aio_error'. */ + ++nthreads; + else + { + /* Reset the running flag. The new request is not running. */ + running = newp->running = yes; + + if (nthreads == 0) + /* We cannot create a thread in the moment and there is + also no thread running. This is a problem. `errno' is + set to EAGAIN if this is only a temporary problem. */ + result = -1; + } + } + } + + /* Enqueue the request in the run queue if it is not yet running. */ + if (running == yes && result == 0) + { + add_request_to_runlist (newp); + + /* If there is a thread waiting for work, then let it know that we + have just given it something to do. */ + if (idle_thread_count > 0) + pthread_cond_signal (&__aio_new_request_notification); + } + + if (result == 0) + newp->running = running; + return result; +} + +/* The main function of the async I/O handling. It enqueues requests + and if necessary starts and handles threads. */ +struct requestlist * +internal_function +__aio_enqueue_request_ctx (aiocb_union *aiocbp, int operation, kctx_t kctx) +{ + int policy, prio; + struct sched_param param; + struct requestlist *newp; + int op = (operation & 0xffff); + + if (op == LIO_SYNC || op == LIO_DSYNC) + { + aiocbp->aiocb.aio_reqprio = 0; + /* FIXME: Kernel doesn't support sync yet. */ + operation &= ~LIO_KTHREAD; + kctx = KCTX_NONE; + } + else if (aiocbp->aiocb.aio_reqprio < 0 + || aiocbp->aiocb.aio_reqprio > AIO_PRIO_DELTA_MAX) + { + /* Invalid priority value. */ + __set_errno (EINVAL); + aiocbp->aiocb.__error_code = EINVAL; + aiocbp->aiocb.__return_value = -1; + return NULL; + } + + if ((operation & LIO_KTHREAD) || kctx != KCTX_NONE) + { + /* io_* is only really asynchronous for O_DIRECT or /dev/raw*. */ + int fl = __fcntl (aiocbp->aiocb.aio_fildes, F_GETFL); + if (fl < 0 || (fl & O_DIRECT) == 0) + { + struct stat64 st; + if (__fxstat64 (_STAT_VER, aiocbp->aiocb.aio_fildes, &st) < 0 + || ! S_ISCHR (st.st_mode) + || major (st.st_rdev) != 162) + { + operation &= ~LIO_KTHREAD; + kctx = KCTX_NONE; + } + } + } + + /* Compute priority for this request. */ + pthread_getschedparam (pthread_self (), &policy, ¶m); + prio = param.sched_priority - aiocbp->aiocb.aio_reqprio; + + /* Get the mutex. */ + pthread_mutex_lock (&__aio_requests_mutex); + + if (operation & LIO_KTHREAD) + { + if (__aio_kioctx == KCTX_NONE && !__have_no_kernel_aio) + { + int res; + INTERNAL_SYSCALL_DECL (err); + + __aio_kioctx = 0; + do + res = INTERNAL_SYSCALL (io_setup, err, 2, 1024, &__aio_kioctx); + while (INTERNAL_SYSCALL_ERROR_P (res, err) + && INTERNAL_SYSCALL_ERRNO (res, err) == EINTR); + if (INTERNAL_SYSCALL_ERROR_P (res, err)) + { + __have_no_kernel_aio = 1; + __aio_kioctx = KCTX_NONE; + } + } + + kctx = __aio_kioctx; + + if (kctx != KCTX_NONE && !__kernel_thread_started + && ((operation & LIO_KTHREAD_REQUIRED) + || aiocbp->aiocb.aio_sigevent.sigev_notify != SIGEV_NONE)) + { + if (__aio_create_kernel_thread () < 0) + kctx = KCTX_NONE; + } + } + + /* Get a new element for the waiting list. */ + newp = get_elem (); + if (newp == NULL) + { + pthread_mutex_unlock (&__aio_requests_mutex); + __set_errno (EAGAIN); + return NULL; + } + newp->aiocbp = aiocbp; +#ifdef BROKEN_THREAD_SIGNALS + newp->caller_pid = (aiocbp->aiocb.aio_sigevent.sigev_notify == SIGEV_SIGNAL + ? getpid () : 0); +#endif + newp->waiting = NULL; + newp->kioctx = kctx; + + aiocbp->aiocb.__abs_prio = prio; + aiocbp->aiocb.__policy = policy; + aiocbp->aiocb.aio_lio_opcode = op; + aiocbp->aiocb.__error_code = EINPROGRESS; + aiocbp->aiocb.__return_value = 0; + + if (newp->kioctx != KCTX_NONE) + { + int res; + INTERNAL_SYSCALL_DECL (err); + + aiocb_union *aiocbp = newp->aiocbp; + struct kiocb *kiocbs[] __attribute__((unused)) = { &newp->kiocb }; + + newp->kiocb.kiocb_data = (uintptr_t) kernel_callback; + switch (op & 127) + { + case LIO_READ: newp->kiocb.kiocb_lio_opcode = IO_CMD_PREAD; break; + case LIO_WRITE: newp->kiocb.kiocb_lio_opcode = IO_CMD_PWRITE; break; + case LIO_SYNC: + case LIO_DSYNC: newp->kiocb.kiocb_lio_opcode = IO_CMD_FSYNC; break; + } + if (op & 128) + newp->kiocb.kiocb_offset = aiocbp->aiocb64.aio_offset; + else + newp->kiocb.kiocb_offset = aiocbp->aiocb.aio_offset; + newp->kiocb.kiocb_fildes = aiocbp->aiocb.aio_fildes; + newp->kiocb.kiocb_buf = (uintptr_t) aiocbp->aiocb.aio_buf; + newp->kiocb.kiocb_nbytes = aiocbp->aiocb.aio_nbytes; + /* FIXME. */ + newp->kiocb.kiocb_req_prio = 0; + res = INTERNAL_SYSCALL (io_submit, err, 3, newp->kioctx, 1, kiocbs); + if (! INTERNAL_SYSCALL_ERROR_P (res, err)) + { + newp->running = allocated; + add_request_to_list (newp, aiocbp->aiocb.aio_fildes, prio); + /* Release the mutex. */ + pthread_mutex_unlock (&__aio_requests_mutex); + return newp; + } + newp->kioctx = KCTX_NONE; + } + + if (__aio_enqueue_user_request (newp)) + { + /* Something went wrong. */ + __aio_free_request (newp); + newp = NULL; + } + + /* Release the mutex. */ + pthread_mutex_unlock (&__aio_requests_mutex); + + return newp; +} + + +static int +wait_for_kernel_requests (int fildes) +{ + pthread_mutex_lock (&__aio_requests_mutex); + + struct requestlist *kreq = __aio_find_kreq_fd (fildes), *req; + int nent = 0; + int ret = 0; + + req = kreq; + while (req) + { + if (req->running == allocated) + ++nent; + req = req->next_prio; + } + + if (nent) + { + if (__aio_create_kernel_thread () < 0) + { + pthread_mutex_unlock (&__aio_requests_mutex); + return -1; + } + +#ifndef DONT_NEED_AIO_MISC_COND + pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +#endif + struct waitlist waitlist[nent]; + int cnt = 0; + + while (kreq) + { + if (kreq->running == allocated) + { +#ifndef DONT_NEED_AIO_MISC_COND + waitlist[cnt].cond = &cond; +#endif + waitlist[cnt].result = NULL; + waitlist[cnt].next = kreq->waiting; + waitlist[cnt].counterp = &nent; + waitlist[cnt].sigevp = NULL; +#ifdef BROKEN_THREAD_SIGNALS + waitlist[cnt].caller_pid = 0; /* Not needed. */ +#endif + kreq->waiting = &waitlist[cnt++]; + } + kreq = kreq->next_prio; + } + +#ifdef DONT_NEED_AIO_MISC_COND + AIO_MISC_WAIT (ret, nent, NULL, 0); +#else + do + pthread_cond_wait (&cond, &__aio_requests_mutex); + while (nent); + + pthread_cond_destroy (&cond); +#endif + } + + pthread_mutex_unlock (&__aio_requests_mutex); + return ret; +} + + +static void * +handle_fildes_io (void *arg) +{ + pthread_t self = pthread_self (); + struct sched_param param; + struct requestlist *runp = (struct requestlist *) arg; + aiocb_union *aiocbp; + int policy; + int fildes; + + pthread_getschedparam (self, &policy, ¶m); + + do + { + /* If runp is NULL, then we were created to service the work queue + in general, not to handle any particular request. In that case we + skip the "do work" stuff on the first pass, and go directly to the + "get work off the work queue" part of this loop, which is near the + end. */ + if (runp == NULL) + pthread_mutex_lock (&__aio_requests_mutex); + else + { + /* Hopefully this request is marked as running. */ + assert (runp->running == allocated); + + /* Update our variables. */ + aiocbp = runp->aiocbp; + fildes = aiocbp->aiocb.aio_fildes; + + /* Change the priority to the requested value (if necessary). */ + if (aiocbp->aiocb.__abs_prio != param.sched_priority + || aiocbp->aiocb.__policy != policy) + { + param.sched_priority = aiocbp->aiocb.__abs_prio; + policy = aiocbp->aiocb.__policy; + pthread_setschedparam (self, policy, ¶m); + } + + /* Process request pointed to by RUNP. We must not be disturbed + by signals. */ + if ((aiocbp->aiocb.aio_lio_opcode & 127) == LIO_READ) + { + if (aiocbp->aiocb.aio_lio_opcode & 128) + aiocbp->aiocb.__return_value = + TEMP_FAILURE_RETRY (__pread64 (fildes, (void *) + aiocbp->aiocb64.aio_buf, + aiocbp->aiocb64.aio_nbytes, + aiocbp->aiocb64.aio_offset)); + else + aiocbp->aiocb.__return_value = + TEMP_FAILURE_RETRY (pread (fildes, + (void *) aiocbp->aiocb.aio_buf, + aiocbp->aiocb.aio_nbytes, + aiocbp->aiocb.aio_offset)); + + if (aiocbp->aiocb.__return_value == -1 && errno == ESPIPE) + /* The Linux kernel is different from others. It returns + ESPIPE if using pread on a socket. Other platforms + simply ignore the offset parameter and behave like + read. */ + aiocbp->aiocb.__return_value = + TEMP_FAILURE_RETRY (read (fildes, + (void *) aiocbp->aiocb64.aio_buf, + aiocbp->aiocb64.aio_nbytes)); + } + else if ((aiocbp->aiocb.aio_lio_opcode & 127) == LIO_WRITE) + { + if (aiocbp->aiocb.aio_lio_opcode & 128) + aiocbp->aiocb.__return_value = + TEMP_FAILURE_RETRY (__pwrite64 (fildes, (const void *) + aiocbp->aiocb64.aio_buf, + aiocbp->aiocb64.aio_nbytes, + aiocbp->aiocb64.aio_offset)); + else + aiocbp->aiocb.__return_value = + TEMP_FAILURE_RETRY (__libc_pwrite (fildes, (const void *) + aiocbp->aiocb.aio_buf, + aiocbp->aiocb.aio_nbytes, + aiocbp->aiocb.aio_offset)); + + if (aiocbp->aiocb.__return_value == -1 && errno == ESPIPE) + /* The Linux kernel is different from others. It returns + ESPIPE if using pwrite on a socket. Other platforms + simply ignore the offset parameter and behave like + write. */ + aiocbp->aiocb.__return_value = + TEMP_FAILURE_RETRY (write (fildes, + (void *) aiocbp->aiocb64.aio_buf, + aiocbp->aiocb64.aio_nbytes)); + } + else if (aiocbp->aiocb.aio_lio_opcode == LIO_DSYNC + || aiocbp->aiocb.aio_lio_opcode == LIO_SYNC) + { + if (wait_for_kernel_requests (fildes) < 0) + { + aiocbp->aiocb.__return_value = -1; + __set_errno (ENOMEM); + } + else if (aiocbp->aiocb.aio_lio_opcode == LIO_DSYNC) + aiocbp->aiocb.__return_value = + TEMP_FAILURE_RETRY (fdatasync (fildes)); + else + aiocbp->aiocb.__return_value = + TEMP_FAILURE_RETRY (fsync (fildes)); + } + else + { + /* This is an invalid opcode. */ + aiocbp->aiocb.__return_value = -1; + __set_errno (EINVAL); + } + + /* Get the mutex. */ + pthread_mutex_lock (&__aio_requests_mutex); + + /* In theory we would need here a write memory barrier since the + callers test using aio_error() whether the request finished + and once this value != EINPROGRESS the field __return_value + must be committed to memory. + + But since the pthread_mutex_lock call involves write memory + barriers as well it is not necessary. */ + + if (aiocbp->aiocb.__return_value == -1) + aiocbp->aiocb.__error_code = errno; + else + aiocbp->aiocb.__error_code = 0; + + /* Send the signal to notify about finished processing of the + request. */ + __aio_notify (runp); + + /* For debugging purposes we reset the running flag of the + finished request. */ + assert (runp->running == allocated); + runp->running = done; + + /* Now dequeue the current request. */ + __aio_remove_request (NULL, runp, 0); + if (runp->next_prio != NULL) + add_request_to_runlist (runp->next_prio); + + /* Free the old element. */ + __aio_free_request (runp); + } + + runp = runlist; + + /* If the runlist is empty, then we sleep for a while, waiting for + something to arrive in it. */ + if (runp == NULL && optim.aio_idle_time >= 0) + { + struct timeval now; + struct timespec wakeup_time; + + ++idle_thread_count; + gettimeofday (&now, NULL); + wakeup_time.tv_sec = now.tv_sec + optim.aio_idle_time; + wakeup_time.tv_nsec = now.tv_usec * 1000; + if (wakeup_time.tv_nsec > 1000000000) + { + wakeup_time.tv_nsec -= 1000000000; + ++wakeup_time.tv_sec; + } + pthread_cond_timedwait (&__aio_new_request_notification, + &__aio_requests_mutex, + &wakeup_time); + --idle_thread_count; + runp = runlist; + } + + if (runp == NULL) + --nthreads; + else + { + assert (runp->running == yes); + runp->running = allocated; + runlist = runp->next_run; + + /* If we have a request to process, and there's still another in + the run list, then we need to either wake up or create a new + thread to service the request that is still in the run list. */ + if (runlist != NULL) + { + /* There are at least two items in the work queue to work on. + If there are other idle threads, then we should wake them + up for these other work elements; otherwise, we should try + to create a new thread. */ + if (idle_thread_count > 0) + pthread_cond_signal (&__aio_new_request_notification); + else if (nthreads < optim.aio_threads) + { + pthread_t thid; + + /* Now try to start a thread. If we fail, no big deal, + because we know that there is at least one thread (us) + that is working on AIO operations. */ + if (aio_create_helper_thread (&thid, handle_fildes_io, NULL) + == 0) + ++nthreads; + } + } + } + + /* Release the mutex. */ + pthread_mutex_unlock (&__aio_requests_mutex); + } + while (runp != NULL); + + return NULL; +} + + +/* Free allocated resources. */ +libc_freeres_fn (free_res) +{ + size_t row; + + for (row = 0; row < pool_max_size; ++row) + free (pool[row]); + + free (pool); +} + + +/* Add newrequest to the runlist. The __abs_prio flag of newrequest must + be correctly set to do this. Also, you had better set newrequest's + "running" flag to "yes" before you release your lock or you'll throw an + assertion. */ +static void +internal_function +add_request_to_runlist (struct requestlist *newrequest) +{ + int prio = newrequest->aiocbp->aiocb.__abs_prio; + struct requestlist *runp; + + if (runlist == NULL || runlist->aiocbp->aiocb.__abs_prio < prio) + { + newrequest->next_run = runlist; + runlist = newrequest; + } + else + { + runp = runlist; + + while (runp->next_run != NULL + && runp->next_run->aiocbp->aiocb.__abs_prio >= prio) + runp = runp->next_run; + + newrequest->next_run = runp->next_run; + runp->next_run = newrequest; + } +} +#endif diff --git a/rtkaio/sysdeps/unix/sysv/linux/kaio_misc.h b/rtkaio/sysdeps/unix/sysv/linux/kaio_misc.h new file mode 100644 index 0000000000..5e0ca19c31 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/kaio_misc.h @@ -0,0 +1,328 @@ +/* Copyright (C) 1997,1999,2000,2001,2002,2003,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. */ + +#ifndef _AIO_MISC_H + +#include <sysdep.h> + +#if !defined __NR_io_setup || !defined __NR_io_destroy \ + || !defined __NR_io_getevents || !defined __NR_io_submit \ + || !defined __NR_io_cancel + +#include <aio_misc.h> + +#else + +#define _AIO_MISC_H 1 +#define USE_KAIO 1 + +#include <aio.h> +#include <pthread.h> +#include <stdint.h> +#include <signal.h> +#include <sysdep.h> +#include <limits.h> + +#ifdef HAVE_FORCED_UNWIND + +/* 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 && --*waitlist->counterp == 0) \ + lll_futex_wake (waitlist->counterp, 1); \ + } while (0) + +# define AIO_MISC_WAIT(result, futex, timeout, cancel) \ + do { \ + volatile int *futexaddr = &futex; \ + 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 (futexaddr, oldval, timeout); \ + if (status != -EWOULDBLOCK) \ + break; \ + \ + oldval = *futexaddr; \ + } \ + 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) + +#endif + +typedef unsigned long kctx_t; +#define KCTX_NONE ~0UL +extern kctx_t __aio_kioctx; + +enum +{ + IO_CMD_PREAD, + IO_CMD_PWRITE, + IO_CMD_FSYNC, + IO_CMD_FDSYNC, + IO_CMD_PREADX, + IO_CMD_POLL +}; + +struct kiocb +{ + uint64_t kiocb_data; + uint64_t kiocb_key; + uint16_t kiocb_lio_opcode; + int16_t kiocb_req_prio; + uint32_t kiocb_fildes; + uint64_t kiocb_buf; + uint64_t kiocb_nbytes; + int64_t kiocb_offset; + int64_t __pad3, __pad4; +}; + +struct kio_event +{ + uint64_t kioe_data; + uint64_t kioe_obj; + int64_t kioe_res; + int64_t kioe_res2; +}; + +/* Extend the operation enum. */ +enum +{ + LIO_DSYNC = LIO_NOP + 1, + LIO_SYNC, + LIO_READ64 = LIO_READ | 128, + LIO_WRITE64 = LIO_WRITE | 128, + LIO_KTHREAD = 0x10000, + LIO_KTHREAD_REQUIRED = 0x20000 +}; + + +/* Union of the two request types. */ +typedef union + { + struct aiocb aiocb; + struct aiocb64 aiocb64; + } aiocb_union; + + +/* Used to synchronize. */ +struct waitlist + { + struct waitlist *next; + + /* The next two fields is used in synchronous io_listio' operations. */ +#ifndef DONT_NEED_AIO_MISC_COND + pthread_cond_t *cond; +#endif + int *result; + + volatile int *counterp; + /* The next field is used in asynchronous `lio_listio' operations. */ + struct sigevent *sigevp; +#ifdef BROKEN_THREAD_SIGNALS + /* XXX See requestlist, it's used to work around the broken signal + handling in Linux. */ + pid_t caller_pid; +#endif + }; + + +/* Status of a request. */ +enum +{ + no, + queued, + yes, + allocated, + done +}; + + +/* Used to queue requests.. */ +struct requestlist + { + struct kiocb kiocb; + kctx_t kioctx; + + int running; + + struct requestlist *last_fd; + struct requestlist *next_fd; + struct requestlist *next_prio; + struct requestlist *next_run; + /* For kioctx != KCTX_NONE requests we are doubly linked. */ +#define prev_prio next_run + + /* Pointer to the actual data. */ + aiocb_union *aiocbp; + +#ifdef BROKEN_THREAD_SIGNALS + /* PID of the initiator thread. + XXX This is only necessary for the broken signal handling on Linux. */ + pid_t caller_pid; +#endif + + /* List of waiting processes. */ + struct waitlist *waiting; + }; + + +/* Lock for global I/O list of requests. */ +extern pthread_mutex_t __aio_requests_mutex attribute_hidden; + + +/* Enqueue request. */ +extern struct requestlist *__aio_enqueue_request_ctx (aiocb_union *aiocbp, + int operation, + kctx_t kctx) + attribute_hidden internal_function; + +#define __aio_enqueue_request(aiocbp, operation) \ + __aio_enqueue_request_ctx (aiocbp, operation | LIO_KTHREAD, KCTX_NONE) + +/* Find request entry for given AIO control block. */ +extern struct requestlist *__aio_find_req (aiocb_union *elem) + attribute_hidden internal_function; + +/* Find request entry for given file descriptor. */ +extern struct requestlist *__aio_find_req_fd (int fildes) + attribute_hidden internal_function; + +/* Find request entry for given file descriptor. */ +extern struct requestlist *__aio_find_kreq_fd (int fildes) + attribute_hidden internal_function; + +/* Remove request from the list. */ +extern void __aio_remove_request (struct requestlist *last, + struct requestlist *req, int all) + attribute_hidden internal_function; + +extern void __aio_remove_krequest (struct requestlist *req) + attribute_hidden internal_function; + +/* Release the entry for the request. */ +extern void __aio_free_request (struct requestlist *req) + attribute_hidden internal_function; + +/* Notify initiator of request and tell this everybody listening. */ +extern void __aio_notify (struct requestlist *req) + attribute_hidden internal_function; + +/* Notify initiator of request. */ +#ifdef BROKEN_THREAD_SIGNALS +extern int __aio_notify_only (struct sigevent *sigev, pid_t caller_pid) + attribute_hidden internal_function; +#else +extern int __aio_notify_only (struct sigevent *sigev) + attribute_hidden internal_function; +#endif + +/* Send the signal. */ +extern int __aio_sigqueue (int sig, const union sigval val, pid_t caller_pid) + attribute_hidden internal_function; + +extern int __aio_wait_for_events (kctx_t kctx, const struct timespec *timeout) + attribute_hidden internal_function; + +extern void __aio_read_one_event (void) attribute_hidden internal_function; + +extern int __aio_create_kernel_thread (void) + attribute_hidden internal_function; + +extern int __have_no_kernel_aio attribute_hidden; +extern int __kernel_thread_started attribute_hidden; + +#ifndef BROKEN_THREAD_SIGNALS +# define aio_start_notify_thread __aio_start_notify_thread +# define aio_create_helper_thread __aio_create_helper_thread + +extern inline void +__aio_start_notify_thread (void) +{ + sigset_t ss; + sigemptyset (&ss); + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, NULL, _NSIG / 8); +} + +extern inline int +__aio_create_helper_thread (pthread_t *threadp, void *(*tf) (void *), void *arg) +{ + pthread_attr_t attr; + + /* Make sure the thread is created detached. */ + pthread_attr_init (&attr); + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + + /* The helper thread needs only very little resources. */ + (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN); + + /* Block all signals in the helper thread. To do this thoroughly we + temporarily have to block all signals here. */ + sigset_t ss; + sigset_t oss; + sigfillset (&ss); + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, &oss, _NSIG / 8); + + int ret = pthread_create (threadp, &attr, tf, arg); + + /* Restore the signal mask. */ + INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &oss, NULL, + _NSIG / 8); + + (void) pthread_attr_destroy (&attr); + return ret; +} +#endif + +#endif +#endif /* aio_misc.h */ diff --git a/rtkaio/sysdeps/unix/sysv/linux/kaio_notify.c b/rtkaio/sysdeps/unix/sysv/linux/kaio_notify.c new file mode 100644 index 0000000000..8b03909bc4 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/kaio_notify.c @@ -0,0 +1,2 @@ +#include <kaio_misc.h> +#include <aio_notify.c> diff --git a/rtkaio/sysdeps/unix/sysv/linux/kaio_read.c b/rtkaio/sysdeps/unix/sysv/linux/kaio_read.c new file mode 100644 index 0000000000..0c5db34879 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/kaio_read.c @@ -0,0 +1,2 @@ +#include <kaio_misc.h> +#include <aio_read.c> diff --git a/rtkaio/sysdeps/unix/sysv/linux/kaio_read64.c b/rtkaio/sysdeps/unix/sysv/linux/kaio_read64.c new file mode 100644 index 0000000000..62db3d45bd --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/kaio_read64.c @@ -0,0 +1,2 @@ +#include <kaio_misc.h> +#include <aio_read64.c> diff --git a/rtkaio/sysdeps/unix/sysv/linux/kaio_return.c b/rtkaio/sysdeps/unix/sysv/linux/kaio_return.c new file mode 100644 index 0000000000..1d9f6cbabb --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/kaio_return.c @@ -0,0 +1,50 @@ +/* Return exit value of asynchronous I/O request. + Copyright (C) 1997, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. + + 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 use an UGLY hack to prevent gcc from finding us cheating. The + implementation of aio_return and aio_return64 are identical and so + we want to avoid code duplication by using aliases. But gcc sees + the different parameter lists and prints a warning. We define here + a function so that aio_return64 has no prototype. */ +#define aio_return64 XXX +#include <aio.h> +/* And undo the hack. */ +#undef aio_return64 + +#include <kaio_misc.h> + +#ifndef USE_KAIO +#include <aio_return.c> +#else + +#include <errno.h> + +ssize_t +aio_return (aiocbp) + struct aiocb *aiocbp; +{ + if (aiocbp->__error_code == EINPROGRESS) + __aio_read_one_event (); + return aiocbp->__return_value; +} + +weak_alias (aio_return, aio_return64) +#endif diff --git a/rtkaio/sysdeps/unix/sysv/linux/kaio_sigqueue.c b/rtkaio/sysdeps/unix/sysv/linux/kaio_sigqueue.c new file mode 100644 index 0000000000..3a5c5efb0d --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/kaio_sigqueue.c @@ -0,0 +1,2 @@ +#include <kaio_misc.h> +#include <aio_sigqueue.c> diff --git a/rtkaio/sysdeps/unix/sysv/linux/kaio_suspend.c b/rtkaio/sysdeps/unix/sysv/linux/kaio_suspend.c new file mode 100644 index 0000000000..2400c5223c --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/kaio_suspend.c @@ -0,0 +1,327 @@ +/* Suspend until termination of a requests. + Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2006 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. + + 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 use an UGLY hack to prevent gcc from finding us cheating. The + implementations of aio_suspend and aio_suspend64 are identical and so + we want to avoid code duplication by using aliases. But gcc sees + the different parameter lists and prints a warning. We define here + a function so that aio_suspend64 has no prototype. */ +#define aio_suspend64 XXX +#include <aio.h> +/* And undo the hack. */ +#undef aio_suspend64 + +#include <kaio_misc.h> + +#ifndef USE_KAIO +#include <aio_suspend.c> +#else + +#include <assert.h> +#include <errno.h> +#include <stdbool.h> +#include <stdlib.h> +#include <sys/time.h> + +#include <bits/libc-lock.h> +#include <sysdep-cancel.h> + + +struct clparam +{ + const struct aiocb *const *list; + struct waitlist *waitlist; + struct requestlist **requestlist; +#ifndef DONT_NEED_AIO_MISC_COND + pthread_cond_t *cond; +#endif + int nent; +}; + + +static void +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; + + /* Now remove the entry in the waiting list for all requests + which didn't terminate. */ + int cnt = param->nent; + while (cnt-- > 0) + if (param->list[cnt] != NULL + && param->list[cnt]->__error_code == EINPROGRESS) + { + struct waitlist **listp; + + assert (param->requestlist[cnt] != NULL); + + /* There is the chance that we cannot find our entry anymore. This + could happen if the request terminated and restarted again. */ + listp = ¶m->requestlist[cnt]->waiting; + while (*listp != NULL && *listp != ¶m->waitlist[cnt]) + listp = &(*listp)->next; + + if (*listp != NULL) + *listp = (*listp)->next; + } + +#ifndef DONT_NEED_AIO_MISC_COND + /* Release the conditional variable. */ + (void) pthread_cond_destroy (param->cond); +#endif + + /* Release the mutex. */ + pthread_mutex_unlock (&__aio_requests_mutex); +} + + +int +aio_suspend (list, nent, timeout) + const struct aiocb *const list[]; + int nent; + const struct timespec *timeout; +{ + if (__builtin_expect (nent < 0, 0)) + { + __set_errno (EINVAL); + return -1; + } + + struct waitlist waitlist[nent]; + struct requestlist *requestlist[nent]; +#ifndef DONT_NEED_AIO_MISC_COND + pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +#endif + int cnt; + int result = 0; + int cntr = 1; + int total = 0, ktotal = 0; + + /* Request the mutex. */ + pthread_mutex_lock (&__aio_requests_mutex); + + /* There is not yet a finished request. Signal the request that + we are working for it. */ + for (cnt = 0; cnt < nent; ++cnt) + if (list[cnt] != NULL) + { + if (list[cnt]->__error_code == EINPROGRESS) + { + requestlist[cnt] = __aio_find_req ((aiocb_union *) list[cnt]); + + if (requestlist[cnt] != NULL) + { +#ifndef DONT_NEED_AIO_MISC_COND + waitlist[cnt].cond = &cond; +#endif + waitlist[cnt].result = NULL; + waitlist[cnt].next = requestlist[cnt]->waiting; + waitlist[cnt].counterp = &cntr; + waitlist[cnt].sigevp = NULL; +#ifdef BROKEN_THREAD_SIGNALS + waitlist[cnt].caller_pid = 0; /* Not needed. */ +#endif + requestlist[cnt]->waiting = &waitlist[cnt]; + total++; + if (requestlist[cnt]->kioctx != KCTX_NONE) + ktotal++; + } + else + /* We will never suspend. */ + break; + } + else + /* We will never suspend. */ + break; + } + + + /* Only if none of the entries is NULL or finished to be wait. */ + if (cnt == nent && total) + { + struct clparam clparam = + { + .list = list, + .waitlist = waitlist, + .requestlist = requestlist, +#ifndef DONT_NEED_AIO_MISC_COND + .cond = &cond, +#endif + .nent = nent + }; + + pthread_cleanup_push (cleanup, &clparam); + + if (!__kernel_thread_started && ktotal) + { + /* If the kernel aio thread was not started yet all requests + are served by the kernel and there are no other threads running, + read events with mutex hold, so that nobody else can get them + instead of us here. */ + if (SINGLE_THREAD_P && total == ktotal) + { + if (timeout == NULL) + { + while (cntr == 1) + __aio_wait_for_events (__aio_kioctx, NULL); + } + else + { + struct timeval now; + struct timespec abstime, ts; + + __gettimeofday (&now, NULL); + abstime.tv_nsec = timeout->tv_nsec + now.tv_usec * 1000; + abstime.tv_sec = timeout->tv_sec + now.tv_sec; + if (abstime.tv_nsec >= 1000000000) + { + abstime.tv_nsec -= 1000000000; + abstime.tv_sec += 1; + } + + for (;;) + { + result = __aio_wait_for_events (__aio_kioctx, timeout); + if (cntr < 1) + break; + if (result == ETIMEDOUT) + break; + + __gettimeofday (&now, NULL); + if (now.tv_sec > abstime.tv_sec + || (now.tv_sec == abstime.tv_sec + && now.tv_usec * 1000 >= abstime.tv_nsec)) + break; + + ts.tv_nsec = abstime.tv_nsec - now.tv_usec * 1000; + ts.tv_sec = abstime.tv_sec - now.tv_sec; + if (abstime.tv_nsec < now.tv_usec * 1000) + { + ts.tv_nsec += 1000000000; + ts.tv_sec -= 1; + } + timeout = &ts; + } + + if (cntr < 1) + result = 0; + else + result = ETIMEDOUT; + } + total = 0; + } + else if (__aio_create_kernel_thread () < 0) + { + total = 0; + __set_errno (ENOMEM); + result = -1; + } + } + + if (total == 0) + /* Suspending was handled above. */ + ; +#ifdef DONT_NEED_AIO_MISC_COND + else + AIO_MISC_WAIT (result, cntr, timeout, 1); +#else + else if (timeout == NULL) + result = pthread_cond_wait (&cond, &__aio_requests_mutex); + else + { + /* We have to convert the relative timeout value into an + absolute time value with pthread_cond_timedwait expects. */ + struct timeval now; + struct timespec abstime; + + __gettimeofday (&now, NULL); + abstime.tv_nsec = timeout->tv_nsec + now.tv_usec * 1000; + abstime.tv_sec = timeout->tv_sec + now.tv_sec; + if (abstime.tv_nsec >= 1000000000) + { + abstime.tv_nsec -= 1000000000; + abstime.tv_sec += 1; + } + + result = pthread_cond_timedwait (&cond, &__aio_requests_mutex, + &abstime); + } +#endif + + pthread_cleanup_pop (0); + } + + /* Now remove the entry in the waiting list for all requests + which didn't terminate. */ + while (cnt-- > 0) + if (list[cnt] != NULL && list[cnt]->__error_code == EINPROGRESS) + { + struct waitlist **listp; + + assert (requestlist[cnt] != NULL); + + /* There is the chance that we cannot find our entry anymore. This + could happen if the request terminated and restarted again. */ + listp = &requestlist[cnt]->waiting; + while (*listp != NULL && *listp != &waitlist[cnt]) + listp = &(*listp)->next; + + if (*listp != NULL) + *listp = (*listp)->next; + } + +#ifndef DONT_NEED_AIO_MISC_COND + /* Release the conditional variable. */ + if (__builtin_expect (pthread_cond_destroy (&cond) != 0, 0)) + /* This must never happen. */ + abort (); +#endif + + if (result != 0) + { +#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 + form expected from `aio_suspend'. */ + if (result == ETIMEDOUT) + __set_errno (EAGAIN); + else +#endif + __set_errno (result); + + result = -1; + } + + /* Release the mutex. */ + pthread_mutex_unlock (&__aio_requests_mutex); + + return result; +} + +weak_alias (aio_suspend, aio_suspend64) +#endif diff --git a/rtkaio/sysdeps/unix/sysv/linux/kaio_write.c b/rtkaio/sysdeps/unix/sysv/linux/kaio_write.c new file mode 100644 index 0000000000..96863b2cdd --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/kaio_write.c @@ -0,0 +1,2 @@ +#include <kaio_misc.h> +#include <aio_write.c> diff --git a/rtkaio/sysdeps/unix/sysv/linux/kaio_write64.c b/rtkaio/sysdeps/unix/sysv/linux/kaio_write64.c new file mode 100644 index 0000000000..1fa7121dfd --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/kaio_write64.c @@ -0,0 +1,2 @@ +#include <kaio_misc.h> +#include <aio_write64.c> diff --git a/rtkaio/sysdeps/unix/sysv/linux/klio_listio.c b/rtkaio/sysdeps/unix/sysv/linux/klio_listio.c new file mode 100644 index 0000000000..b7676c9f03 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/klio_listio.c @@ -0,0 +1,322 @@ +/* Enqueue and list of read or write requests. + Copyright (C) 1997,1998,1999,2000,2001,2002,2003,2005,2006 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. + + 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. */ + +#include <kaio_misc.h> + +#ifndef USE_KAIO +#include <lio_listio.c> +#else + +#ifndef lio_listio +#include <aio.h> +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> + +#define LIO_OPCODE_BASE 0 +#endif + +#include <shlib-compat.h> + + +/* We need this special structure to handle asynchronous I/O. */ +struct async_waitlist + { + int counter; + struct sigevent sigev; + struct waitlist list[0]; + }; + + +/* The code in glibc 2.1 to glibc 2.4 issued only one event when all + requests submitted with lio_listio finished. The existing practice + is to issue events for the individual requests as well. This is + what the new code does. */ +#if SHLIB_COMPAT (librt, GLIBC_2_1, GLIBC_2_4) +# define LIO_MODE(mode) ((mode) & 127) +# define NO_INDIVIDUAL_EVENT_P(mode) ((mode) & 128) +#else +# define LIO_MODE(mode) mode +# define NO_INDIVIDUAL_EVENT_P(mode) 0 +#endif + + +static int +lio_listio_internal (int mode, struct aiocb *const list[], int nent, + struct sigevent *sig) +{ + struct sigevent defsigev; + struct requestlist *requests[nent]; + int cnt; + volatile int total = 0; + int result = 0, op = 0; + kctx_t kctx = KCTX_NONE; + + if (sig == NULL) + { + defsigev.sigev_notify = SIGEV_NONE; + sig = &defsigev; + } + + /* Request the mutex. */ + pthread_mutex_lock (&__aio_requests_mutex); + + if (LIO_MODE (mode) == LIO_WAIT && ! __have_no_kernel_aio && nent > 0) + { + int res; + INTERNAL_SYSCALL_DECL (err); + + kctx = 0; + do + res = INTERNAL_SYSCALL (io_setup, err, 2, nent, &kctx); + while (INTERNAL_SYSCALL_ERROR_P (res, err) + && INTERNAL_SYSCALL_ERRNO (res, err) == EINTR); + if (INTERNAL_SYSCALL_ERROR_P (res, err)) + { + kctx = KCTX_NONE; + if (INTERNAL_SYSCALL_ERRNO (res, err) == ENOSYS) + __have_no_kernel_aio = 1; + } + } + else if (LIO_MODE (mode) == LIO_NOWAIT) + { + op = LIO_KTHREAD; + if (sig->sigev_notify != SIGEV_NONE) + op = LIO_KTHREAD | LIO_KTHREAD_REQUIRED; + } + op |= LIO_OPCODE_BASE; + + /* Now we can enqueue all requests. Since we already acquired the + mutex the enqueue function need not do this. */ + for (cnt = 0; cnt < nent; ++cnt) + if (list[cnt] != NULL && list[cnt]->aio_lio_opcode != LIO_NOP) + { + if (NO_INDIVIDUAL_EVENT_P (mode)) + list[cnt]->aio_sigevent.sigev_notify = SIGEV_NONE; + requests[cnt] + = __aio_enqueue_request_ctx ((aiocb_union *) list[cnt], + list[cnt]->aio_lio_opcode | op, + kctx); + + if (requests[cnt] != NULL) + /* Successfully enqueued. */ + ++total; + else + /* Signal that we've seen an error. `errno' and the error code + of the aiocb will tell more. */ + result = -1; + } + else + requests[cnt] = NULL; + + if (total == 0) + { + /* We don't have anything to do except signalling if we work + asynchronously. */ + + if (kctx != KCTX_NONE) + { + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (io_destroy, err, 1, kctx); + } + + /* Release the mutex. We do this before raising a signal since the + signal handler might do a `siglongjmp' and then the mutex is + locked forever. */ + pthread_mutex_unlock (&__aio_requests_mutex); + + if (LIO_MODE (mode) == LIO_NOWAIT) + { +#ifdef BROKEN_THREAD_SIGNALS + __aio_notify_only (sig, + sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0); +#else + __aio_notify_only (sig); +#endif + } + + return result; + } + else if (LIO_MODE (mode) == LIO_WAIT) + { +#ifndef DONT_NEED_AIO_MISC_COND + pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + int oldstate; +#endif + struct waitlist waitlist[nent]; + volatile int ktotal = 0; + + total = 0; + for (cnt = 0; cnt < nent; ++cnt) + { + assert (requests[cnt] == NULL || list[cnt] != NULL); + + if (requests[cnt] != NULL && list[cnt]->aio_lio_opcode != LIO_NOP) + { + if (requests[cnt]->kioctx != KCTX_NONE) + { + assert (requests[cnt]->kioctx == kctx); + waitlist[cnt].counterp = &ktotal; + ++ktotal; + } + else + { + waitlist[cnt].counterp = &total; + ++total; + } +#ifndef DONT_NEED_AIO_MISC_COND + waitlist[cnt].cond = &cond; +#endif + waitlist[cnt].result = &result; + waitlist[cnt].next = requests[cnt]->waiting; + waitlist[cnt].sigevp = NULL; +#ifdef BROKEN_THREAD_SIGNALS + waitlist[cnt].caller_pid = 0; /* Not needed. */ +#endif + requests[cnt]->waiting = &waitlist[cnt]; + } + } + + while (ktotal > 0) + __aio_wait_for_events (kctx, NULL); +#ifdef DONT_NEED_AIO_MISC_COND + AIO_MISC_WAIT (result, total, NULL, 0); +#else + /* Since `pthread_cond_wait'/`pthread_cond_timedwait' are cancellation + points we must be careful. We added entries to the waiting lists + which we must remove. So defer cancellation for now. */ + pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate); + + while (total > 0) + pthread_cond_wait (&cond, &__aio_requests_mutex); + + /* Now it's time to restore the cancellation state. */ + pthread_setcancelstate (oldstate, NULL); + + /* Release the conditional variable. */ + if (pthread_cond_destroy (&cond) != 0) + /* This must never happen. */ + abort (); +#endif + + if (kctx != KCTX_NONE) + { + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (io_destroy, err, 1, kctx); + } + + /* If any of the I/O requests failed, return -1 and set errno. */ + if (result != 0) + { + __set_errno (result == EINTR ? EINTR : EIO); + result = -1; + } + } + else if (sig->sigev_notify != SIGEV_NONE) + { + struct async_waitlist *waitlist; + + waitlist = (struct async_waitlist *) + malloc (sizeof (struct async_waitlist) + + (nent * sizeof (struct waitlist))); + + if (waitlist == NULL) + { + __set_errno (EAGAIN); + result = -1; + } + else + { +#ifdef BROKEN_THREAD_SIGNALS + pid_t caller_pid = sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0; +#endif + total = 0; + + for (cnt = 0; cnt < nent; ++cnt) + { + assert (requests[cnt] == NULL || list[cnt] != NULL); + + if (requests[cnt] != NULL + && list[cnt]->aio_lio_opcode != LIO_NOP) + { +#ifndef DONT_NEED_AIO_MISC_COND + waitlist->list[cnt].cond = NULL; +#endif + waitlist->list[cnt].result = NULL; + waitlist->list[cnt].next = requests[cnt]->waiting; + waitlist->list[cnt].counterp = &waitlist->counter; + waitlist->list[cnt].sigevp = &waitlist->sigev; +#ifdef BROKEN_THREAD_SIGNALS + waitlist->list[cnt].caller_pid = caller_pid; +#endif + requests[cnt]->waiting = &waitlist->list[cnt]; + ++total; + } + } + + waitlist->counter = total; + waitlist->sigev = *sig; + } + } + + /* Release the mutex. */ + pthread_mutex_unlock (&__aio_requests_mutex); + + return result; +} + + +#if SHLIB_COMPAT (librt, GLIBC_2_1, GLIBC_2_4) +int +attribute_compat_text_section +__lio_listio_21 (int mode, struct aiocb *const list[], int nent, + struct sigevent *sig) +{ + /* Check arguments. */ + if (mode != LIO_WAIT && mode != LIO_NOWAIT) + { + __set_errno (EINVAL); + return -1; + } + + return lio_listio_internal (mode | LIO_NO_INDIVIDUAL_EVENT, list, nent, sig); +} +compat_symbol (librt, __lio_listio_21, lio_listio, GLIBC_2_1); +#endif + + +int +__lio_listio_item_notify (int mode, struct aiocb *const list[], int nent, + struct sigevent *sig) +{ + /* Check arguments. */ + if (mode != LIO_WAIT && mode != LIO_NOWAIT) + { + __set_errno (EINVAL); + return -1; + } + + return lio_listio_internal (mode, list, nent, sig); +} +versioned_symbol (librt, __lio_listio_item_notify, lio_listio, GLIBC_2_4); + +#endif diff --git a/rtkaio/sysdeps/unix/sysv/linux/klio_listio64.c b/rtkaio/sysdeps/unix/sysv/linux/klio_listio64.c new file mode 100644 index 0000000000..937cf1a9f0 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/klio_listio64.c @@ -0,0 +1,40 @@ +/* Enqueue and list of read or write requests, 64bit offset version. + Copyright (C) 1997, 1998, 1999, 2003, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. + + 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. */ + +#include <kaio_misc.h> + +#ifndef USE_KAIO +#include <lio_listio64.c> +#else + +#include <aio.h> +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> + +#define lio_listio lio_listio64 +#define __lio_listio_21 __lio_listio64_21 +#define __lio_listio_item_notify __lio_listio64_item_notify +#define aiocb aiocb64 +#define LIO_OPCODE_BASE 128 +#include <klio_listio.c> + +#endif diff --git a/rtkaio/sysdeps/unix/sysv/linux/powerpc/Makefile b/rtkaio/sysdeps/unix/sysv/linux/powerpc/Makefile new file mode 100644 index 0000000000..ead21fb111 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/powerpc/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),rtkaio) +librtkaio-routines += rtkaio-sysdep +endif diff --git a/rtkaio/sysdeps/unix/sysv/linux/powerpc/powerpc64/Versions b/rtkaio/sysdeps/unix/sysv/linux/powerpc/powerpc64/Versions new file mode 100644 index 0000000000..7443c81d6a --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/powerpc/powerpc64/Versions @@ -0,0 +1,9 @@ +%ifdef HAVE_FORCED_UNWIND +librtkaio { + GLIBC_2.3.3 { + # Changed timer_t. + timer_create; timer_delete; timer_getoverrun; timer_gettime; + timer_settime; + } +} +%endif diff --git a/rtkaio/sysdeps/unix/sysv/linux/powerpc/rtkaio-sysdep.c b/rtkaio/sysdeps/unix/sysv/linux/powerpc/rtkaio-sysdep.c new file mode 100644 index 0000000000..ff0440aa83 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/powerpc/rtkaio-sysdep.c @@ -0,0 +1 @@ +#include <rt-sysdep.c> diff --git a/rtkaio/sysdeps/unix/sysv/linux/s390/Makefile b/rtkaio/sysdeps/unix/sysv/linux/s390/Makefile new file mode 100644 index 0000000000..ead21fb111 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/s390/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),rtkaio) +librtkaio-routines += rtkaio-sysdep +endif diff --git a/rtkaio/sysdeps/unix/sysv/linux/s390/rtkaio-sysdep.S b/rtkaio/sysdeps/unix/sysv/linux/s390/rtkaio-sysdep.S new file mode 100644 index 0000000000..11ee214b23 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/s390/rtkaio-sysdep.S @@ -0,0 +1 @@ +#include <rt-sysdep.S> diff --git a/rtkaio/sysdeps/unix/sysv/linux/s390/s390-64/Versions b/rtkaio/sysdeps/unix/sysv/linux/s390/s390-64/Versions new file mode 100644 index 0000000000..7443c81d6a --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/s390/s390-64/Versions @@ -0,0 +1,9 @@ +%ifdef HAVE_FORCED_UNWIND +librtkaio { + GLIBC_2.3.3 { + # Changed timer_t. + timer_create; timer_delete; timer_getoverrun; timer_gettime; + timer_settime; + } +} +%endif diff --git a/rtkaio/sysdeps/unix/sysv/linux/sparc/Makefile b/rtkaio/sysdeps/unix/sysv/linux/sparc/Makefile new file mode 100644 index 0000000000..ead21fb111 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/sparc/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),rtkaio) +librtkaio-routines += rtkaio-sysdep +endif diff --git a/rtkaio/sysdeps/unix/sysv/linux/sparc/Versions b/rtkaio/sysdeps/unix/sysv/linux/sparc/Versions new file mode 100644 index 0000000000..b2d59a9140 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/sparc/Versions @@ -0,0 +1,6 @@ +librtkaio { + GLIBC_2.3 { + # AIO functions. + aio_cancel; aio_cancel64; + } +} diff --git a/rtkaio/sysdeps/unix/sysv/linux/sparc/kaio_cancel.c b/rtkaio/sysdeps/unix/sysv/linux/sparc/kaio_cancel.c new file mode 100644 index 0000000000..6e345e1643 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/sparc/kaio_cancel.c @@ -0,0 +1,33 @@ +#include <shlib-compat.h> + +#define aio_cancel64 XXX +#include <aio.h> +#undef aio_cancel64 +#include <errno.h> + +extern __typeof (aio_cancel) __new_aio_cancel; +extern __typeof (aio_cancel) __old_aio_cancel; + +#define aio_cancel __new_aio_cancel + +#include <sysdeps/unix/sysv/linux/kaio_cancel.c> + +#undef aio_cancel +strong_alias (__new_aio_cancel, __new_aio_cancel64); +versioned_symbol (librt, __new_aio_cancel, aio_cancel, GLIBC_2_3); +versioned_symbol (librt, __new_aio_cancel64, aio_cancel64, GLIBC_2_3); + +#if SHLIB_COMPAT (librt, GLIBC_2_1, GLIBC_2_3) + +#undef ECANCELED +#define aio_cancel __old_aio_cancel +#define ECANCELED 125 + +#include <sysdeps/unix/sysv/linux/kaio_cancel.c> + +#undef aio_cancel +strong_alias (__old_aio_cancel, __old_aio_cancel64); +compat_symbol (librt, __old_aio_cancel, aio_cancel, GLIBC_2_1); +compat_symbol (librt, __old_aio_cancel64, aio_cancel64, GLIBC_2_1); + +#endif diff --git a/rtkaio/sysdeps/unix/sysv/linux/sparc/rtkaio-sysdep.c b/rtkaio/sysdeps/unix/sysv/linux/sparc/rtkaio-sysdep.c new file mode 100644 index 0000000000..ff0440aa83 --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/sparc/rtkaio-sysdep.c @@ -0,0 +1 @@ +#include <rt-sysdep.c> diff --git a/rtkaio/sysdeps/unix/sysv/linux/sparc/sparc64/Versions b/rtkaio/sysdeps/unix/sysv/linux/sparc/sparc64/Versions new file mode 100644 index 0000000000..7443c81d6a --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/sparc/sparc64/Versions @@ -0,0 +1,9 @@ +%ifdef HAVE_FORCED_UNWIND +librtkaio { + GLIBC_2.3.3 { + # Changed timer_t. + timer_create; timer_delete; timer_getoverrun; timer_gettime; + timer_settime; + } +} +%endif diff --git a/rtkaio/sysdeps/unix/sysv/linux/syscalls.list b/rtkaio/sysdeps/unix/sysv/linux/syscalls.list new file mode 100644 index 0000000000..686b8d5d2e --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/syscalls.list @@ -0,0 +1,5 @@ +# File name Caller Syscall name Args Strong name Weak names + +kaio_mq_timedsend - mq_timedsend Ci:ipiip __GI_mq_timedsend mq_timedsend +kaio_mq_timedreceive - mq_timedreceive Ci:ipipp __GI_mq_timedreceive mq_timedreceive +kaio_mq_setattr - mq_getsetattr i:ipp __GI_mq_setattr mq_setattr diff --git a/rtkaio/sysdeps/unix/sysv/linux/x86_64/Versions b/rtkaio/sysdeps/unix/sysv/linux/x86_64/Versions new file mode 100644 index 0000000000..7443c81d6a --- /dev/null +++ b/rtkaio/sysdeps/unix/sysv/linux/x86_64/Versions @@ -0,0 +1,9 @@ +%ifdef HAVE_FORCED_UNWIND +librtkaio { + GLIBC_2.3.3 { + # Changed timer_t. + timer_create; timer_delete; timer_getoverrun; timer_gettime; + timer_settime; + } +} +%endif diff --git a/rtkaio/tst-aio.c b/rtkaio/tst-aio.c new file mode 100644 index 0000000000..e6ff5ee4fe --- /dev/null +++ b/rtkaio/tst-aio.c @@ -0,0 +1 @@ +#include <rt/tst-aio.c> diff --git a/rtkaio/tst-aio10.c b/rtkaio/tst-aio10.c new file mode 100644 index 0000000000..d99730124f --- /dev/null +++ b/rtkaio/tst-aio10.c @@ -0,0 +1 @@ +#include <rt/tst-aio10.c> diff --git a/rtkaio/tst-aio2.c b/rtkaio/tst-aio2.c new file mode 100644 index 0000000000..d2ce9279aa --- /dev/null +++ b/rtkaio/tst-aio2.c @@ -0,0 +1 @@ +#include <rt/tst-aio2.c> diff --git a/rtkaio/tst-aio3.c b/rtkaio/tst-aio3.c new file mode 100644 index 0000000000..ecbbef855f --- /dev/null +++ b/rtkaio/tst-aio3.c @@ -0,0 +1 @@ +#include <rt/tst-aio3.c> diff --git a/rtkaio/tst-aio4.c b/rtkaio/tst-aio4.c new file mode 100644 index 0000000000..2399daf921 --- /dev/null +++ b/rtkaio/tst-aio4.c @@ -0,0 +1 @@ +#include <rt/tst-aio4.c> diff --git a/rtkaio/tst-aio5.c b/rtkaio/tst-aio5.c new file mode 100644 index 0000000000..4455676c3b --- /dev/null +++ b/rtkaio/tst-aio5.c @@ -0,0 +1 @@ +#include <rt/tst-aio5.c> diff --git a/rtkaio/tst-aio6.c b/rtkaio/tst-aio6.c new file mode 100644 index 0000000000..d4db530378 --- /dev/null +++ b/rtkaio/tst-aio6.c @@ -0,0 +1 @@ +#include <rt/tst-aio6.c> diff --git a/rtkaio/tst-aio64.c b/rtkaio/tst-aio64.c new file mode 100644 index 0000000000..8ac7ae033a --- /dev/null +++ b/rtkaio/tst-aio64.c @@ -0,0 +1 @@ +#include <rt/tst-aio64.c> diff --git a/rtkaio/tst-aio7.c b/rtkaio/tst-aio7.c new file mode 100644 index 0000000000..9d05ac6b80 --- /dev/null +++ b/rtkaio/tst-aio7.c @@ -0,0 +1 @@ +#include <rt/tst-aio7.c> diff --git a/rtkaio/tst-aio8.c b/rtkaio/tst-aio8.c new file mode 100644 index 0000000000..9fd46cc22c --- /dev/null +++ b/rtkaio/tst-aio8.c @@ -0,0 +1 @@ +#include <rt/tst-aio8.c> diff --git a/rtkaio/tst-aio9.c b/rtkaio/tst-aio9.c new file mode 100644 index 0000000000..320b05f2d9 --- /dev/null +++ b/rtkaio/tst-aio9.c @@ -0,0 +1 @@ +#include <rt/tst-aio9.c> diff --git a/rtkaio/tst-aiod.c b/rtkaio/tst-aiod.c new file mode 100644 index 0000000000..a8b58106dc --- /dev/null +++ b/rtkaio/tst-aiod.c @@ -0,0 +1,307 @@ +/* Tests for AIO in librt. + Copyright (C) 1998, 2000, 2002, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. + + 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. */ + +#include <aio.h> +#include <errno.h> +#include <error.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include "tst-aiod.h" + + +/* Prototype for our test function. */ +extern void do_prepare (int argc, char *argv[]); +extern int do_test (int argc, char *argv[]); + +/* We have a preparation function. */ +#define PREPARE do_prepare + +/* We might need a bit longer timeout. */ +#define TIMEOUT 20 /* sec */ + +/* This defines the `main' function and some more. */ +#include <test-skeleton.c> + + +/* These are for the temporary file we generate. */ +char *name; +int fd; +char *tmpbuf; +int blksz = 100; + +void +do_prepare (int argc, char *argv[]) +{ + size_t name_len; + + name_len = strlen (test_dir); + name = malloc (name_len + sizeof ("/aioXXXXXX")); + mempcpy (mempcpy (name, test_dir, name_len), + "/aioXXXXXX", sizeof ("/aioXXXXXX")); + add_temp_file (name); + + /* Open our test file. */ + fd = mkstemp (name); + if (fd == -1) + error (EXIT_FAILURE, errno, "cannot open test file `%s'", name); + + int sz = set_o_direct (fd); + if (sz != -1) + { + blksz = sz; + printf ("Using O_DIRECT with block size %d\n", blksz); + } +} + + +static int +test_file (const void *buf, size_t size, int fd, const char *msg) +{ + struct stat st; + char *tmp = tmpbuf; + + errno = 0; + if (fstat (fd, &st) < 0) + { + error (0, errno, "%s: failed stat", msg); + return 1; + } + + if (st.st_size != (off_t) size) + { + error (0, errno, "%s: wrong size: %lu, should be %lu", + msg, (unsigned long int) st.st_size, (unsigned long int) size); + return 1; + } + + if (pread (fd, tmp, size, 0) != (ssize_t) size) + { + error (0, errno, "%s: failed pread", msg); + return 1; + } + + if (memcmp (buf, tmp, size) != 0) + { + error (0, errno, "%s: failed comparison", msg); + return 1; + } + + printf ("%s test ok\n", msg); + + return 0; +} + + +static int +do_wait (struct aiocb **cbp, size_t nent, int allowed_err) +{ + int go_on; + size_t cnt; + int result = 0; + + do + { + aio_suspend ((const struct aiocb *const *) cbp, nent, NULL); + go_on = 0; + for (cnt = 0; cnt < nent; ++cnt) + if (cbp[cnt] != NULL) + { + if (aio_error (cbp[cnt]) == EINPROGRESS) + go_on = 1; + else + { + if (aio_return (cbp[cnt]) == -1 + && (allowed_err == 0 + || aio_error (cbp[cnt]) != allowed_err)) + { + error (0, aio_error (cbp[cnt]), "Operation failed\n"); + result = 1; + } + cbp[cnt] = NULL; + } + } + } + while (go_on); + + return result; +} + + +int +do_test (int argc, char *argv[]) +{ + struct aiocb cbs[10]; + struct aiocb cbs_fsync; + struct aiocb *cbp[10]; + struct aiocb *cbp_fsync[1]; + char *buf; + size_t cnt; + int result = 0; + + buf = mmap (NULL, 20 * blksz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + tmpbuf = buf + 10 * blksz; + if (buf == MAP_FAILED) + { + error (0, errno, "mmap failed"); + return 1; + } + + /* Preparation. */ + for (cnt = 0; cnt < 10; ++cnt) + { + cbs[cnt].aio_fildes = fd; + cbs[cnt].aio_reqprio = 0; + cbs[cnt].aio_buf = memset (&buf[cnt * blksz], '0' + cnt, blksz); + cbs[cnt].aio_nbytes = blksz; + cbs[cnt].aio_offset = cnt * blksz; + cbs[cnt].aio_sigevent.sigev_notify = SIGEV_NONE; + + cbp[cnt] = &cbs[cnt]; + } + + /* First a simple test. */ + for (cnt = 10; cnt > 0; ) + if (aio_write (cbp[--cnt]) < 0 && errno == ENOSYS) + { + error (0, 0, "no aio support in this configuration"); + return 0; + } + /* Wait 'til the results are there. */ + result |= do_wait (cbp, 10, 0); + /* Test this. */ + result |= test_file (buf, 10 * blksz, fd, "aio_write"); + + /* Read now as we've written it. */ + memset (buf, '\0', 10 * blksz); + /* Issue the commands. */ + for (cnt = 10; cnt > 0; ) + { + --cnt; + cbp[cnt] = &cbs[cnt]; + aio_read (cbp[cnt]); + } + /* Wait 'til the results are there. */ + result |= do_wait (cbp, 10, 0); + /* Test this. */ + for (cnt = 0; cnt < 10 * blksz; ++cnt) + if (buf[cnt] != '0' + (cnt / blksz)) + { + result = 1; + error (0, 0, "comparison failed for aio_read test"); + break; + } + + if (cnt == 10 * blksz) + puts ("aio_read test ok"); + + /* Remove the test file contents. */ + if (ftruncate (fd, 0) < 0) + { + error (0, errno, "ftruncate failed\n"); + result = 1; + } + + /* Test lio_listio. */ + for (cnt = 0; cnt < 10; ++cnt) + { + cbs[cnt].aio_lio_opcode = LIO_WRITE; + cbp[cnt] = &cbs[cnt]; + } + /* Issue the command. */ + lio_listio (LIO_WAIT, cbp, 10, NULL); + /* ...and immediately test it since we started it in wait mode. */ + result |= test_file (buf, 10 * blksz, fd, "lio_listio (write)"); + + /* Test aio_fsync. */ + cbs_fsync.aio_fildes = fd; + cbs_fsync.aio_sigevent.sigev_notify = SIGEV_NONE; + cbp_fsync[0] = &cbs_fsync; + + /* Remove the test file contents first. */ + if (ftruncate (fd, 0) < 0) + { + error (0, errno, "ftruncate failed\n"); + result = 1; + } + + /* Write again. */ + for (cnt = 10; cnt > 0; ) + aio_write (cbp[--cnt]); + + if (aio_fsync (O_SYNC, &cbs_fsync) < 0) + { + error (0, errno, "aio_fsync failed\n"); + result = 1; + } + result |= do_wait (cbp_fsync, 1, 0); + + /* ...and test since all data should be on disk now. */ + result |= test_file (buf, 10 * blksz, fd, "aio_fsync (aio_write)"); + + /* Test aio_cancel. */ + /* Remove the test file contents first. */ + if (ftruncate (fd, 0) < 0) + { + error (0, errno, "ftruncate failed\n"); + result = 1; + } + + /* Write again. */ + for (cnt = 10; cnt > 0; ) + aio_write (cbp[--cnt]); + + /* Cancel all requests. */ + if (aio_cancel (fd, NULL) == -1) + printf ("aio_cancel (fd, NULL) cannot cancel anything\n"); + + result |= do_wait (cbp, 10, ECANCELED); + + /* Another test for aio_cancel. */ + /* Remove the test file contents first. */ + if (ftruncate (fd, 0) < 0) + { + error (0, errno, "ftruncate failed\n"); + result = 1; + } + + /* Write again. */ + for (cnt = 10; cnt > 0; ) + { + --cnt; + cbp[cnt] = &cbs[cnt]; + aio_write (cbp[cnt]); + } + puts ("finished3"); + + /* Cancel all requests. */ + for (cnt = 10; cnt > 0; ) + if (aio_cancel (fd, cbp[--cnt]) == -1) + /* This is not an error. The request can simply be finished. */ + printf ("aio_cancel (fd, cbp[%Zd]) cannot be canceled\n", cnt); + puts ("finished2"); + + result |= do_wait (cbp, 10, ECANCELED); + + puts ("finished"); + + return result; +} diff --git a/rtkaio/tst-aiod.h b/rtkaio/tst-aiod.h new file mode 100644 index 0000000000..57f0e48ce5 --- /dev/null +++ b/rtkaio/tst-aiod.h @@ -0,0 +1,52 @@ +/* Tests for AIO in librt. + Copyright (C) 1998, 2000, 2002, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. + + 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. */ + +#include <fcntl.h> +#include <sys/mman.h> +#include <unistd.h> + +static int +set_o_direct (int fd) +{ + int ret = -1; +#ifdef O_DIRECT + if (fcntl (fd, F_SETFL, fcntl (fd, F_GETFL) | O_DIRECT) >= 0) + { + int pgsz = sysconf (_SC_PAGESIZE); + char *buf = mmap (NULL, 16 * pgsz, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (buf != MAP_FAILED) + { + memset (buf, 0, 16 * pgsz); + for (int sz = 256; sz <= 16 * pgsz; sz *= 2) + if (write (fd, buf, sz) > 0) + { + ret = sz; + break; + } + ftruncate64 (fd, 0); + munmap (buf, 16 * pgsz); + } + if (ret < 0) + fcntl (fd, F_SETFL, fcntl (fd, F_GETFL) & ~O_DIRECT); + } +#endif + return ret; +} diff --git a/rtkaio/tst-aiod2.c b/rtkaio/tst-aiod2.c new file mode 100644 index 0000000000..c516797c71 --- /dev/null +++ b/rtkaio/tst-aiod2.c @@ -0,0 +1,128 @@ +/* Test for notification mechanism in lio_listio. + Copyright (C) 2000, 2002, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000. + + 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. */ + +#include <aio.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include "tst-aiod.h" + + +static pthread_barrier_t b; + + +static void +thrfct (sigval_t arg) +{ + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("thread: barrier_wait failed"); + exit (1); + } +} + + +static int +do_test (int argc, char *argv[]) +{ + char name[] = "/tmp/aio2.XXXXXX"; + int fd; + struct aiocb *arr[1]; + struct aiocb cb; + static const char buf[] = "Hello World\n"; + + fd = mkstemp (name); + if (fd == -1) + { + printf ("cannot open temp name: %m\n"); + return 1; + } + + unlink (name); + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + arr[0] = &cb; + + void *p; + int sz = set_o_direct (fd); + if (sz != -1) + { + int err = posix_memalign (&p, sz, sz); + if (err) + { + errno = err; + printf ("cannot allocate memory: %m\n"); + return 1; + } + memcpy (p, buf, sizeof (buf) - 1); + memset (p + sizeof (buf) - 1, ' ', sz - sizeof (buf) + 1); + printf ("Using O_DIRECT with block size %d\n", sz); + } + else + { + p = (void *) buf; + sz = sizeof (buf) - 1; + } + + cb.aio_fildes = fd; + cb.aio_lio_opcode = LIO_WRITE; + cb.aio_reqprio = 0; + cb.aio_buf = p; + cb.aio_nbytes = sz; + cb.aio_offset = 0; + cb.aio_sigevent.sigev_notify = SIGEV_THREAD; + cb.aio_sigevent.sigev_notify_function = thrfct; + cb.aio_sigevent.sigev_notify_attributes = NULL; + cb.aio_sigevent.sigev_value.sival_ptr = NULL; + + if (lio_listio (LIO_WAIT, arr, 1, NULL) < 0) + { + if (errno == ENOSYS) + { + puts ("no aio support in this configuration"); + return 0; + } + printf ("lio_listio failed: %m\n"); + return 1; + } + + puts ("lio_listio returned"); + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return 1; + } + + puts ("all OK"); + + return 0; +} + +#include "../test-skeleton.c" diff --git a/rtkaio/tst-aiod3.c b/rtkaio/tst-aiod3.c new file mode 100644 index 0000000000..aac04f3771 --- /dev/null +++ b/rtkaio/tst-aiod3.c @@ -0,0 +1,131 @@ +/* Test for notification mechanism in lio_listio. + Copyright (C) 2000, 2002, 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. */ + +#include <aio.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include "tst-aiod.h" + + +static pthread_barrier_t b; + + +static void +thrfct (sigval_t arg) +{ + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: barrier_wait failed"); + exit (1); + } +} + + +static int +do_test (int argc, char *argv[]) +{ + char name[] = "/tmp/aio3.XXXXXX"; + int fd; + struct aiocb *arr[1]; + struct aiocb cb; + static const char buf[] = "Hello World\n"; + + fd = mkstemp (name); + if (fd == -1) + { + printf ("cannot open temp name: %m\n"); + return 1; + } + + unlink (name); + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + arr[0] = &cb; + + void *p; + int sz = set_o_direct (fd); + if (sz != -1) + { + int err = posix_memalign (&p, sz, sz); + if (err) + { + errno = err; + printf ("cannot allocate memory: %m\n"); + return 1; + } + memcpy (p, buf, sizeof (buf) - 1); + memset (p + sizeof (buf) - 1, ' ', sz - sizeof (buf) + 1); + printf ("Using O_DIRECT with block size %d\n", sz); + } + else + { + p = (void *) buf; + sz = sizeof (buf) - 1; + } + + cb.aio_fildes = fd; + cb.aio_lio_opcode = LIO_WRITE; + cb.aio_reqprio = 0; + cb.aio_buf = p; + cb.aio_nbytes = sz; + cb.aio_offset = 0; + cb.aio_sigevent.sigev_notify = SIGEV_THREAD; + cb.aio_sigevent.sigev_notify_function = thrfct; + cb.aio_sigevent.sigev_notify_attributes = NULL; + cb.aio_sigevent.sigev_value.sival_ptr = NULL; + + if (lio_listio (LIO_NOWAIT, arr, 1, NULL) < 0) + { + if (errno == ENOSYS) + { + puts ("no aio support in this configuration"); + return 0; + } + printf ("lio_listio failed: %m\n"); + return 1; + } + + if (aio_suspend ((const struct aiocb *const *) arr, 1, NULL) < 0) + { + printf ("aio_suspend failed: %m\n"); + return 1; + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: barrier_wait failed"); + return 1; + } + + puts ("all OK"); + + return 0; +} + +#include "../test-skeleton.c" diff --git a/rtkaio/tst-aiod4.c b/rtkaio/tst-aiod4.c new file mode 100644 index 0000000000..d9ce18ae28 --- /dev/null +++ b/rtkaio/tst-aiod4.c @@ -0,0 +1,182 @@ +/* Test for completion signal handling. + Copyright (C) 2000, 2001, 2002, 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. */ + +#include <aio.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include "tst-aiod.h" + +/* We might need a bit longer timeout. */ +#define TIMEOUT 10 /* sec */ + +int my_signo; + +volatile sig_atomic_t flag; + + +static void +sighandler (const int signo) +{ + flag = signo; +} + +static int +wait_flag (void) +{ + while (flag == 0) + { + puts ("Sleeping..."); + sleep (1); + } + + if (flag != my_signo) + { + printf ("signal handler received wrong signal, flag is %d\n", flag); + return 1; + } + + return 0; +} + +#ifndef SIGRTMIN +# define SIGRTMIN -1 +# define SIGRTMAX -1 +#endif + +static int +do_test (int argc, char *argv[]) +{ + char name[] = "/tmp/aio4.XXXXXX"; + int fd; + struct aiocb *arr[1]; + struct aiocb cb; + static const char buf[] = "Hello World\n"; + struct aioinit init = {10, 20, 0}; + struct sigaction sa; + struct sigevent ev; + + if (SIGRTMIN == -1) + { + printf ("RT signals not supported.\n"); + return 0; + } + + /* Select a signal from the middle of the available choices... */ + my_signo = (SIGRTMAX + SIGRTMIN) / 2; + + fd = mkstemp (name); + if (fd == -1) + { + printf ("cannot open temp name: %m\n"); + return 1; + } + + unlink (name); + + /* Test also aio_init. */ + aio_init (&init); + + arr[0] = &cb; + + void *p; + int sz = set_o_direct (fd); + if (sz != -1) + { + int err = posix_memalign (&p, sz, sz); + if (err) + { + errno = err; + printf ("cannot allocate memory: %m\n"); + return 1; + } + memcpy (p, buf, sizeof (buf) - 1); + memset (p + sizeof (buf) - 1, ' ', sz - sizeof (buf) + 1); + printf ("Using O_DIRECT with block size %d\n", sz); + } + else + { + p = (void *) buf; + sz = sizeof (buf) - 1; + } + + cb.aio_fildes = fd; + cb.aio_lio_opcode = LIO_WRITE; + cb.aio_reqprio = 0; + cb.aio_buf = p; + cb.aio_nbytes = sz; + cb.aio_offset = 0; + cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL; + cb.aio_sigevent.sigev_notify_function = NULL; + cb.aio_sigevent.sigev_notify_attributes = NULL; + cb.aio_sigevent.sigev_signo = my_signo; + cb.aio_sigevent.sigev_value.sival_ptr = NULL; + + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_notify_function = NULL; + ev.sigev_notify_attributes = NULL; + ev.sigev_signo = my_signo; + + sa.sa_handler = sighandler; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_RESTART; + + if (sigaction (my_signo, &sa, NULL) < 0) + { + printf ("sigaction failed: %m\n"); + return 1; + } + + flag = 0; + /* First use aio_write. */ + if (aio_write (arr[0]) < 0) + { + if (errno == ENOSYS) + { + puts ("no aio support in this configuration"); + return 0; + } + printf ("aio_write failed: %m\n"); + return 1; + } + + if (wait_flag ()) + return 1; + + puts ("aio_write OK"); + + flag = 0; + /* Again with lio_listio. */ + if (lio_listio (LIO_NOWAIT, arr, 1, &ev) < 0) + { + printf ("lio_listio failed: %m\n"); + return 1; + } + + if (wait_flag ()) + return 1; + + puts ("all OK"); + + return 0; +} + +#include "../test-skeleton.c" diff --git a/rtkaio/tst-aiod5.c b/rtkaio/tst-aiod5.c new file mode 100644 index 0000000000..780f1b6028 --- /dev/null +++ b/rtkaio/tst-aiod5.c @@ -0,0 +1,152 @@ +/* Test for completion thread handling. + Copyright (C) 2000, 2002, 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. */ + +#include <aio.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include "tst-aiod.h" + +/* We might need a bit longer timeout. */ +#define TIMEOUT 10 /* sec */ + +#define MY_SIVAL 27 + +volatile sig_atomic_t flag; + + +static void +callback (sigval_t s) +{ + flag = s.sival_int; +} + +static int +wait_flag (void) +{ + while (flag == 0) + { + puts ("Sleeping..."); + sleep (1); + } + + if (flag != MY_SIVAL) + { + printf ("signal handler received wrong signal, flag is %d\n", flag); + return 1; + } + + return 0; +} + + +static int +do_test (int argc, char *argv[]) +{ + char name[] = "/tmp/aio5.XXXXXX"; + int fd; + struct aiocb *arr[1]; + struct aiocb cb; + static const char buf[] = "Hello World\n"; + struct sigevent ev; + + fd = mkstemp (name); + if (fd == -1) + { + printf ("cannot open temp name: %m\n"); + return 1; + } + + unlink (name); + + arr[0] = &cb; + + void *p; + int sz = set_o_direct (fd); + if (sz != -1) + { + int err = posix_memalign (&p, sz, sz); + if (err) + { + errno = err; + printf ("cannot allocate memory: %m\n"); + return 1; + } + memcpy (p, buf, sizeof (buf) - 1); + memset (p + sizeof (buf) - 1, ' ', sz - sizeof (buf) + 1); + printf ("Using O_DIRECT with block size %d\n", sz); + } + else + { + p = (void *) buf; + sz = sizeof (buf) - 1; + } + + cb.aio_fildes = fd; + cb.aio_lio_opcode = LIO_WRITE; + cb.aio_reqprio = 0; + cb.aio_buf = p; + cb.aio_nbytes = sz; + cb.aio_offset = 0; + cb.aio_sigevent.sigev_notify = SIGEV_THREAD; + cb.aio_sigevent.sigev_notify_function = callback; + cb.aio_sigevent.sigev_notify_attributes = NULL; + cb.aio_sigevent.sigev_value.sival_int = MY_SIVAL; + + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = callback; + ev.sigev_notify_attributes = NULL; + ev.sigev_value.sival_int = MY_SIVAL; + + /* First use aio_write. */ + if (aio_write (arr[0]) < 0) + { + if (errno == ENOSYS) + { + puts ("no aio support in this configuration"); + return 0; + } + printf ("aio_write failed: %m\n"); + return 1; + } + + if (wait_flag ()) + return 1; + + puts ("aio_write OK"); + + flag = 0; + /* Again with lio_listio. */ + if (lio_listio (LIO_NOWAIT, arr, 1, &ev) < 0) + { + printf ("lio_listio failed: %m\n"); + return 1; + } + + if (wait_flag ()) + return 1; + + puts ("all OK"); + + return 0; +} + +#include "../test-skeleton.c" diff --git a/rtkaio/tst-aiod64.c b/rtkaio/tst-aiod64.c new file mode 100644 index 0000000000..3b8f014421 --- /dev/null +++ b/rtkaio/tst-aiod64.c @@ -0,0 +1,308 @@ +/* Tests for 64bit AIO in librt. + Copyright (C) 1998, 1999, 2000, 2002, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. + + 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. */ + +#define _LARGEFILE_SOURCE 1 +#include <aio.h> +#include <errno.h> +#include <error.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include "tst-aiod.h" + + +/* Prototype for our test function. */ +extern void do_prepare (int argc, char *argv[]); +extern int do_test (int argc, char *argv[]); + +/* We have a preparation function. */ +#define PREPARE do_prepare + +/* We might need a bit longer timeout. */ +#define TIMEOUT 20 /* sec */ + +/* This defines the `main' function and some more. */ +#include <test-skeleton.c> + + +/* These are for the temporary file we generate. */ +char *name; +int fd; +char *tmpbuf; +int blksz = 100; + +void +do_prepare (int argc, char *argv[]) +{ + size_t name_len; + + name_len = strlen (test_dir); + name = malloc (name_len + sizeof ("/aioXXXXXX")); + mempcpy (mempcpy (name, test_dir, name_len), + "/aioXXXXXX", sizeof ("/aioXXXXXX")); + add_temp_file (name); + + /* Open our test file. */ + fd = mkstemp (name); + if (fd == -1) + error (EXIT_FAILURE, errno, "cannot open test file `%s'", name); + + int sz = set_o_direct (fd); + if (sz != -1) + { + blksz = sz; + printf ("Using O_DIRECT with block size %d\n", blksz); + } +} + + +static int +test_file (const void *buf, size_t size, int fd, const char *msg) +{ + struct stat st; + char *tmp = tmpbuf; + + errno = 0; + if (fstat (fd, &st) < 0) + { + error (0, errno, "%s: failed stat", msg); + return 1; + } + + if (st.st_size != (off_t) size) + { + error (0, errno, "%s: wrong size: %lu, should be %lu", + msg, (unsigned long int) st.st_size, (unsigned long int) size); + return 1; + } + + if (pread (fd, tmp, size, 0) != (ssize_t) size) + { + error (0, errno, "%s: failed pread", msg); + return 1; + } + + if (memcmp (buf, tmp, size) != 0) + { + error (0, errno, "%s: failed comparison", msg); + return 1; + } + + printf ("%s test ok\n", msg); + + return 0; +} + + +static int +do_wait (struct aiocb64 **cbp, size_t nent, int allowed_err) +{ + int go_on; + size_t cnt; + int result = 0; + + do + { + aio_suspend64 ((const struct aiocb64 *const *) cbp, nent, NULL); + go_on = 0; + for (cnt = 0; cnt < nent; ++cnt) + if (cbp[cnt] != NULL) + { + if (aio_error64 (cbp[cnt]) == EINPROGRESS) + go_on = 1; + else + { + if (aio_return64 (cbp[cnt]) == -1 + && (allowed_err == 0 + || aio_error64 (cbp[cnt]) != allowed_err)) + { + error (0, aio_error64 (cbp[cnt]), "Operation failed\n"); + result = 1; + } + cbp[cnt] = NULL; + } + } + } + while (go_on); + + return result; +} + + +int +do_test (int argc, char *argv[]) +{ + struct aiocb64 cbs[10]; + struct aiocb64 cbs_fsync; + struct aiocb64 *cbp[10]; + struct aiocb64 *cbp_fsync[1]; + char *buf; + size_t cnt; + int result = 0; + + buf = mmap (NULL, 20 * blksz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + tmpbuf = buf + 10 * blksz; + if (buf == MAP_FAILED) + { + error (0, errno, "mmap failed"); + return 1; + } + + /* Preparation. */ + for (cnt = 0; cnt < 10; ++cnt) + { + cbs[cnt].aio_fildes = fd; + cbs[cnt].aio_reqprio = 0; + cbs[cnt].aio_buf = memset (&buf[cnt * blksz], '0' + cnt, blksz); + cbs[cnt].aio_nbytes = blksz; + cbs[cnt].aio_offset = cnt * blksz; + cbs[cnt].aio_sigevent.sigev_notify = SIGEV_NONE; + + cbp[cnt] = &cbs[cnt]; + } + + /* First a simple test. */ + for (cnt = 10; cnt > 0; ) + if (aio_write64 (cbp[--cnt]) < 0 && errno == ENOSYS) + { + error (0, 0, "no aio support in this configuration"); + return 0; + } + /* Wait 'til the results are there. */ + result |= do_wait (cbp, 10, 0); + /* Test this. */ + result |= test_file (buf, 10 * blksz, fd, "aio_write"); + + /* Read now as we've written it. */ + memset (buf, '\0', 10 * blksz); + /* Issue the commands. */ + for (cnt = 10; cnt > 0; ) + { + --cnt; + cbp[cnt] = &cbs[cnt]; + aio_read64 (cbp[cnt]); + } + /* Wait 'til the results are there. */ + result |= do_wait (cbp, 10, 0); + /* Test this. */ + for (cnt = 0; cnt < 10 * blksz; ++cnt) + if (buf[cnt] != '0' + (cnt / blksz)) + { + result = 1; + error (0, 0, "comparison failed for aio_read test"); + break; + } + + if (cnt == 10 * blksz) + puts ("aio_read test ok"); + + /* Remove the test file contents. */ + if (ftruncate64 (fd, 0) < 0) + { + error (0, errno, "ftruncate failed\n"); + result = 1; + } + + /* Test lio_listio. */ + for (cnt = 0; cnt < 10; ++cnt) + { + cbs[cnt].aio_lio_opcode = LIO_WRITE; + cbp[cnt] = &cbs[cnt]; + } + /* Issue the command. */ + lio_listio64 (LIO_WAIT, cbp, 10, NULL); + /* ...and immediately test it since we started it in wait mode. */ + result |= test_file (buf, 10 * blksz, fd, "lio_listio (write)"); + + /* Test aio_fsync. */ + cbs_fsync.aio_fildes = fd; + cbs_fsync.aio_sigevent.sigev_notify = SIGEV_NONE; + cbp_fsync[0] = &cbs_fsync; + + /* Remove the test file contents first. */ + if (ftruncate64 (fd, 0) < 0) + { + error (0, errno, "ftruncate failed\n"); + result = 1; + } + + /* Write again. */ + for (cnt = 10; cnt > 0; ) + aio_write64 (cbp[--cnt]); + + if (aio_fsync64 (O_SYNC, &cbs_fsync) < 0) + { + error (0, errno, "aio_fsync failed\n"); + result = 1; + } + result |= do_wait (cbp_fsync, 1, 0); + + /* ...and test since all data should be on disk now. */ + result |= test_file (buf, 10 * blksz, fd, "aio_fsync (aio_write)"); + + /* Test aio_cancel. */ + /* Remove the test file contents first. */ + if (ftruncate64 (fd, 0) < 0) + { + error (0, errno, "ftruncate failed\n"); + result = 1; + } + + /* Write again. */ + for (cnt = 10; cnt > 0; ) + aio_write64 (cbp[--cnt]); + + /* Cancel all requests. */ + if (aio_cancel64 (fd, NULL) == -1) + printf ("aio_cancel64 (fd, NULL) cannot cancel anything\n"); + + result |= do_wait (cbp, 10, ECANCELED); + + /* Another test for aio_cancel. */ + /* Remove the test file contents first. */ + if (ftruncate64 (fd, 0) < 0) + { + error (0, errno, "ftruncate failed\n"); + result = 1; + } + + /* Write again. */ + for (cnt = 10; cnt > 0; ) + { + --cnt; + cbp[cnt] = &cbs[cnt]; + aio_write64 (cbp[cnt]); + } + puts ("finished3"); + + /* Cancel all requests. */ + for (cnt = 10; cnt > 0; ) + if (aio_cancel64 (fd, cbp[--cnt]) == -1) + /* This is not an error. The request can simply be finished. */ + printf ("aio_cancel64 (fd, cbp[%Zd]) cannot be canceled\n", cnt); + puts ("finished2"); + + result |= do_wait (cbp, 10, ECANCELED); + + puts ("finished"); + + return result; +} diff --git a/rtkaio/tst-clock.c b/rtkaio/tst-clock.c new file mode 100644 index 0000000000..2066fb048a --- /dev/null +++ b/rtkaio/tst-clock.c @@ -0,0 +1 @@ +#include <rt/tst-clock.c> diff --git a/rtkaio/tst-clock2.c b/rtkaio/tst-clock2.c new file mode 100644 index 0000000000..7d3b7b9c24 --- /dev/null +++ b/rtkaio/tst-clock2.c @@ -0,0 +1 @@ +#include <rt/tst-clock2.c> diff --git a/rtkaio/tst-clock_nanosleep.c b/rtkaio/tst-clock_nanosleep.c new file mode 100644 index 0000000000..eaa3740a70 --- /dev/null +++ b/rtkaio/tst-clock_nanosleep.c @@ -0,0 +1 @@ +#include <rt/tst-clock_nanosleep.c> diff --git a/rtkaio/tst-cpuclock1.c b/rtkaio/tst-cpuclock1.c new file mode 100644 index 0000000000..9d4ca46da0 --- /dev/null +++ b/rtkaio/tst-cpuclock1.c @@ -0,0 +1 @@ +#include <rt/tst-cpuclock1.c> diff --git a/rtkaio/tst-cpuclock2.c b/rtkaio/tst-cpuclock2.c new file mode 100644 index 0000000000..4967d2de53 --- /dev/null +++ b/rtkaio/tst-cpuclock2.c @@ -0,0 +1 @@ +#include <rt/tst-cpuclock2.c> diff --git a/rtkaio/tst-cputimer1.c b/rtkaio/tst-cputimer1.c new file mode 100644 index 0000000000..2ed6d554a0 --- /dev/null +++ b/rtkaio/tst-cputimer1.c @@ -0,0 +1 @@ +#include <rt/tst-cputimer1.c> diff --git a/rtkaio/tst-cputimer2.c b/rtkaio/tst-cputimer2.c new file mode 100644 index 0000000000..f1e200adae --- /dev/null +++ b/rtkaio/tst-cputimer2.c @@ -0,0 +1 @@ +#include <rt/tst-cputimer2.c> diff --git a/rtkaio/tst-cputimer3.c b/rtkaio/tst-cputimer3.c new file mode 100644 index 0000000000..880edaf6ed --- /dev/null +++ b/rtkaio/tst-cputimer3.c @@ -0,0 +1 @@ +#include <rt/tst-cputimer3.c> diff --git a/rtkaio/tst-mqueue.h b/rtkaio/tst-mqueue.h new file mode 100644 index 0000000000..2f9e38053d --- /dev/null +++ b/rtkaio/tst-mqueue.h @@ -0,0 +1 @@ +#include <rt/tst-mqueue.h> diff --git a/rtkaio/tst-mqueue1.c b/rtkaio/tst-mqueue1.c new file mode 100644 index 0000000000..a2a2a81cb2 --- /dev/null +++ b/rtkaio/tst-mqueue1.c @@ -0,0 +1 @@ +#include <rt/tst-mqueue1.c> diff --git a/rtkaio/tst-mqueue2.c b/rtkaio/tst-mqueue2.c new file mode 100644 index 0000000000..373ab29cbb --- /dev/null +++ b/rtkaio/tst-mqueue2.c @@ -0,0 +1 @@ +#include <rt/tst-mqueue2.c> diff --git a/rtkaio/tst-mqueue3.c b/rtkaio/tst-mqueue3.c new file mode 100644 index 0000000000..95a2ea34f6 --- /dev/null +++ b/rtkaio/tst-mqueue3.c @@ -0,0 +1 @@ +#include <rt/tst-mqueue3.c> diff --git a/rtkaio/tst-mqueue4.c b/rtkaio/tst-mqueue4.c new file mode 100644 index 0000000000..f5ae4056bf --- /dev/null +++ b/rtkaio/tst-mqueue4.c @@ -0,0 +1 @@ +#include <rt/tst-mqueue4.c> diff --git a/rtkaio/tst-mqueue5.c b/rtkaio/tst-mqueue5.c new file mode 100644 index 0000000000..7e8ecf9cec --- /dev/null +++ b/rtkaio/tst-mqueue5.c @@ -0,0 +1 @@ +#include <rt/tst-mqueue5.c> diff --git a/rtkaio/tst-mqueue6.c b/rtkaio/tst-mqueue6.c new file mode 100644 index 0000000000..42172c61dc --- /dev/null +++ b/rtkaio/tst-mqueue6.c @@ -0,0 +1 @@ +#include <rt/tst-mqueue6.c> diff --git a/rtkaio/tst-mqueue7.c b/rtkaio/tst-mqueue7.c new file mode 100644 index 0000000000..ad8f27e3eb --- /dev/null +++ b/rtkaio/tst-mqueue7.c @@ -0,0 +1 @@ +#include <rt/tst-mqueue7.c> diff --git a/rtkaio/tst-mqueue8.c b/rtkaio/tst-mqueue8.c new file mode 100644 index 0000000000..ca280394f7 --- /dev/null +++ b/rtkaio/tst-mqueue8.c @@ -0,0 +1 @@ +#include <rt/tst-mqueue8.c> diff --git a/rtkaio/tst-mqueue9.c b/rtkaio/tst-mqueue9.c new file mode 100644 index 0000000000..0c5aa2b90b --- /dev/null +++ b/rtkaio/tst-mqueue9.c @@ -0,0 +1 @@ +#include <rt/tst-mqueue9.c> diff --git a/rtkaio/tst-shm.c b/rtkaio/tst-shm.c new file mode 100644 index 0000000000..7ad3b21757 --- /dev/null +++ b/rtkaio/tst-shm.c @@ -0,0 +1 @@ +#include <rt/tst-shm.c> diff --git a/rtkaio/tst-timer.c b/rtkaio/tst-timer.c new file mode 100644 index 0000000000..dab887907f --- /dev/null +++ b/rtkaio/tst-timer.c @@ -0,0 +1 @@ +#include <rt/tst-timer.c> diff --git a/rtkaio/tst-timer2.c b/rtkaio/tst-timer2.c new file mode 100644 index 0000000000..85e87f9e3d --- /dev/null +++ b/rtkaio/tst-timer2.c @@ -0,0 +1 @@ +#include <rt/tst-timer2.c> diff --git a/rtkaio/tst-timer3.c b/rtkaio/tst-timer3.c new file mode 100644 index 0000000000..014afd76a6 --- /dev/null +++ b/rtkaio/tst-timer3.c @@ -0,0 +1 @@ +#include <rt/tst-timer3.c> diff --git a/rtkaio/tst-timer4.c b/rtkaio/tst-timer4.c new file mode 100644 index 0000000000..f409255388 --- /dev/null +++ b/rtkaio/tst-timer4.c @@ -0,0 +1 @@ +#include <rt/tst-timer4.c> diff --git a/rtkaio/tst-timer5.c b/rtkaio/tst-timer5.c new file mode 100644 index 0000000000..e66933c742 --- /dev/null +++ b/rtkaio/tst-timer5.c @@ -0,0 +1 @@ +#include <rt/tst-timer5.c> |