From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-qt1-x834.google.com (mail-qt1-x834.google.com [IPv6:2607:f8b0:4864:20::834]) by sourceware.org (Postfix) with ESMTPS id 476483877415 for ; Mon, 21 Jun 2021 18:37:11 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 476483877415 Received: by mail-qt1-x834.google.com with SMTP id r7so14165109qta.12 for ; Mon, 21 Jun 2021 11:37:11 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=iU7tITyzq0kk0BLBlUMksVTZegRV7hC2m4EJit1Apbs=; b=c6JTLG9rAFfCeVrJa8adQaar/E5GxCDzMQwdlfG1WzXvGls/T6gz83GP6P7APNStQ2 1U7teDgeTgHZgQe/y1pVuOR9SHZN8vQQnpSgMrpHfCFsDAddyDkBbnFjFOUcLoQnG0fH cHTBENcDEH4QK21wzuwYdYKzz6n9CEupDYovhnHENpmpVVLzEZQAdtLCjJIphg2nrUfr kC0HXqDhHDHJTPcpmmZVeZrCwCt3zNkZGSXO8hfNhk3oHu5NWoHwIG57C12nghlnWYnP XjsKz0CPXqKYj5b3IFFT2AIfdnVq8wpOSaUjsStrXgxYLSqqF4I9lAe9g3QH6FHs6Txd ipRg== X-Gm-Message-State: AOAM532g8R9wXieZ+XJD+d5Fqb68KIcrRjtSTXizXgtwnLkWvwWw+J22 GYJIA22Ec7M0R1SPJO3rKcOxIVGw9TZFKA== X-Google-Smtp-Source: ABdhPJxrwcZm0qxuTAFJwx61/pq46RrLqp6BaZ30QD+x+6rFjUHcSXLAfEHNN/B3YPrnl8sMg34KLw== X-Received: by 2002:a05:622a:64b:: with SMTP id a11mr10241743qtb.364.1624300630356; Mon, 21 Jun 2021 11:37:10 -0700 (PDT) Received: from [192.168.1.108] ([177.194.59.218]) by smtp.gmail.com with ESMTPSA id k9sm10614728qtq.30.2021.06.21.11.37.08 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 21 Jun 2021 11:37:09 -0700 (PDT) Subject: Re: [PATCH 07/34] rt: Move generic implementation from sysdeps/pthread to rt To: Florian Weimer , libc-alpha@sourceware.org References: <8cb9f3202c5e581b3ca114c52b6c68cafc7b8a5b.1623956057.git.fweimer@redhat.com> From: Adhemerval Zanella Message-ID: Date: Mon, 21 Jun 2021 15:37:07 -0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.8.1 MIME-Version: 1.0 In-Reply-To: <8cb9f3202c5e581b3ca114c52b6c68cafc7b8a5b.1623956057.git.fweimer@redhat.com> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-12.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, NICE_REPLY_A, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 21 Jun 2021 18:37:24 -0000 On 17/06/2021 15:57, Florian Weimer via Libc-alpha wrote: > The pthread-based implementation is the generic one. Replacing > the stubs makes it clear that they do not have to be adjusted for > the libpthread move. > > Result of: > > git mv -f sysdeps/pthread/aio_misc.h sysdeps/generic/ > git mv sysdeps/pthread/timer_routines.c sysdeps/htl/ > git mv -f sysdeps/pthread/{aio,lio,timer}_*.c rt/ > > Followed by manual adjustment of the #include paths in > sysdeps/unix/sysv/linux/wordsize-64, and a move of the version > definitions formerly in sysdeps/pthread/Versions. LGTM, thanks. Reviewed-by: Adhemerval Zanella > --- > rt/Versions | 4 + > rt/aio_cancel.c | 129 +++- > rt/aio_error.c | 12 +- > rt/aio_fsync.c | 26 +- > rt/aio_misc.c | 699 ++++++++++++++++- > rt/aio_notify.c | 144 +++- > rt/aio_read.c | 18 +- > rt/aio_read64.c | 32 +- > rt/aio_suspend.c | 237 +++++- > rt/aio_write.c | 18 +- > rt/aio_write64.c | 32 +- > rt/lio_listio.c | 236 +++++- > rt/lio_listio64.c | 33 +- > rt/timer_create.c | 156 +++- > rt/timer_delete.c | 58 +- > rt/timer_getoverr.c | 33 +- > rt/timer_gettime.c | 64 +- > rt/timer_settime.c | 120 ++- > sysdeps/generic/aio_misc.h | 83 +- > sysdeps/{pthread => htl}/timer_routines.c | 0 > sysdeps/pthread/Versions | 5 - > sysdeps/pthread/aio_cancel.c | 157 ---- > sysdeps/pthread/aio_error.c | 48 -- > sysdeps/pthread/aio_fsync.c | 57 -- > sysdeps/pthread/aio_misc.c | 721 ------------------ > sysdeps/pthread/aio_misc.h | 122 --- > sysdeps/pthread/aio_notify.c | 157 ---- > sysdeps/pthread/aio_read.c | 30 - > sysdeps/pthread/aio_read64.c | 30 - > sysdeps/pthread/aio_suspend.c | 263 ------- > sysdeps/pthread/aio_write.c | 30 - > sysdeps/pthread/aio_write64.c | 30 - > sysdeps/pthread/lio_listio.c | 248 ------ > sysdeps/pthread/lio_listio64.c | 33 - > sysdeps/pthread/timer_create.c | 166 ---- > sysdeps/pthread/timer_delete.c | 68 -- > sysdeps/pthread/timer_getoverr.c | 43 -- > sysdeps/pthread/timer_gettime.c | 74 -- > sysdeps/pthread/timer_settime.c | 131 ---- > sysdeps/unix/sysv/linux/alpha/aio_cancel.c | 4 +- > sysdeps/unix/sysv/linux/sparc/aio_cancel.c | 4 +- > .../unix/sysv/linux/wordsize-64/aio_read.c | 2 +- > .../unix/sysv/linux/wordsize-64/aio_write.c | 2 +- > .../unix/sysv/linux/wordsize-64/lio_listio.c | 2 +- > 44 files changed, 2017 insertions(+), 2544 deletions(-) > rename sysdeps/{pthread => htl}/timer_routines.c (100%) > delete mode 100644 sysdeps/pthread/Versions > delete mode 100644 sysdeps/pthread/aio_cancel.c > delete mode 100644 sysdeps/pthread/aio_error.c > delete mode 100644 sysdeps/pthread/aio_fsync.c > delete mode 100644 sysdeps/pthread/aio_misc.c > delete mode 100644 sysdeps/pthread/aio_misc.h > delete mode 100644 sysdeps/pthread/aio_notify.c > delete mode 100644 sysdeps/pthread/aio_read.c > delete mode 100644 sysdeps/pthread/aio_read64.c > delete mode 100644 sysdeps/pthread/aio_suspend.c > delete mode 100644 sysdeps/pthread/aio_write.c > delete mode 100644 sysdeps/pthread/aio_write64.c > delete mode 100644 sysdeps/pthread/lio_listio.c > delete mode 100644 sysdeps/pthread/lio_listio64.c > delete mode 100644 sysdeps/pthread/timer_create.c > delete mode 100644 sysdeps/pthread/timer_delete.c > delete mode 100644 sysdeps/pthread/timer_getoverr.c > delete mode 100644 sysdeps/pthread/timer_gettime.c > delete mode 100644 sysdeps/pthread/timer_settime.c > > diff --git a/rt/Versions b/rt/Versions > index 309486be1e..26c6d1ac63 100644 > --- a/rt/Versions > +++ b/rt/Versions > @@ -47,6 +47,10 @@ librt { > mq_timedsend; > mq_unlink; > } > + GLIBC_2.4 { > + lio_listio; > + lio_listio64; > + } > GLIBC_2.7 { > __mq_open_2; > } Ok. > diff --git a/rt/aio_cancel.c b/rt/aio_cancel.c > index dba1e45044..63fd88f36c 100644 > --- a/rt/aio_cancel.c > +++ b/rt/aio_cancel.c > @@ -1,6 +1,7 @@ > -/* Cancel requests associated with given file descriptor. Stub version. > - Copyright (C) 2001-2021 Free Software Foundation, Inc. > +/* Cancel requests associated with given file descriptor. > + Copyright (C) 1997-2021 Free Software Foundation, Inc. > This file is part of the GNU C Library. > + Contributed by Ulrich Drepper , 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 > @@ -22,21 +23,135 @@ > 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 > /* And undo the hack. */ > #undef aio_cancel64 > +#endif > > +#include > #include > +#include > + > +#include > + > > int > aio_cancel (int fildes, struct aiocb *aiocbp) > { > - __set_errno (ENOSYS); > - return -1; > + 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) > + { > + not_found: > + pthread_mutex_unlock (&__aio_requests_mutex); > + __set_errno (EINVAL); > + return -1; > + } > + > + while (req->aiocbp != (aiocb_union *) aiocbp) > + { > + last = req; > + req = req->next_prio; > + if (req == NULL) > + goto not_found; > + } > + > + /* 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 > + { > + /* 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); > + } > + } > + } > + > + /* 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) > - > -stub_warning (aio_cancel) > -stub_warning (aio_cancel64) > +#endif Ok. > diff --git a/rt/aio_error.c b/rt/aio_error.c > index 730b64b5e9..ed664ae0ef 100644 > --- a/rt/aio_error.c > +++ b/rt/aio_error.c > @@ -28,11 +28,21 @@ > /* And undo the hack. */ > #undef aio_error64 > > +#include > + > > int > aio_error (const struct aiocb *aiocbp) > { > - return aiocbp->__error_code; > + int ret; > + > + /* Acquire the mutex to make sure all operations for this request are > + complete. */ > + pthread_mutex_lock(&__aio_requests_mutex); > + ret = aiocbp->__error_code; > + pthread_mutex_unlock(&__aio_requests_mutex); > + > + return ret; > } > > weak_alias (aio_error, aio_error64) Ok. > diff --git a/rt/aio_fsync.c b/rt/aio_fsync.c > index 86727246f8..5a52e2fec0 100644 > --- a/rt/aio_fsync.c > +++ b/rt/aio_fsync.c > @@ -1,6 +1,7 @@ > -/* Synchronize I/O in given file descriptor. Stub version. > - Copyright (C) 2001-2021 Free Software Foundation, Inc. > +/* Synchronize I/O in given file descriptor. > + Copyright (C) 1997-2021 Free Software Foundation, Inc. > This file is part of the GNU C Library. > + Contributed by Ulrich Drepper , 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 > @@ -26,24 +27,31 @@ > #include > /* And undo the hack. */ > #undef aio_fsync64 > - > #include > #include > > +#include > + > + > int > aio_fsync (int op, struct aiocb *aiocbp) > { > - if (op != O_SYNC && op != O_DSYNC) > + if (op != O_DSYNC && __builtin_expect (op != O_SYNC, 0)) > { > __set_errno (EINVAL); > return -1; > } > > - __set_errno (ENOSYS); > - return -1; > + /* Verify that this is an open file descriptor. */ > + if (__glibc_unlikely (fcntl (aiocbp->aio_fildes, F_GETFL) == -1)) > + { > + __set_errno (EBADF); > + return -1; > + } > + > + return (__aio_enqueue_request ((aiocb_union *) aiocbp, > + op == O_SYNC ? LIO_SYNC : LIO_DSYNC) == NULL > + ? -1 : 0); > } > > weak_alias (aio_fsync, aio_fsync64) > - > -stub_warning (aio_fsync) > -stub_warning (aio_fsync64) Ok. > diff --git a/rt/aio_misc.c b/rt/aio_misc.c > index 2332f3ed53..b95f07d9d3 100644 > --- a/rt/aio_misc.c > +++ b/rt/aio_misc.c > @@ -1,6 +1,7 @@ > -/* Handle general operations. Stub version. > - Copyright (C) 2001-2021 Free Software Foundation, Inc. > +/* Handle general operations. > + Copyright (C) 1997-2021 Free Software Foundation, Inc. > This file is part of the GNU C Library. > + Contributed by Ulrich Drepper , 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 > @@ -17,12 +18,704 @@ > . */ > > #include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > #include > > -/* This file is for internal code needed by the aio_* implementation. */ > +#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); > + > +/* 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; > + > +/* 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; > + > +/* 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 simultaneous 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 > +__aio_free_request (struct requestlist *elem) > +{ > + elem->running = no; > + elem->next_prio = freelist; > + freelist = elem; > +} > + > + > +struct requestlist * > +__aio_find_req (aiocb_union *elem) > +{ > + struct requestlist *runp = requests; > + int fildes = elem->aiocb.aio_fildes; > + > + 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; > + } > + > + return runp; > +} > + > + > +struct requestlist * > +__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); > +} > + > + > +void > +__aio_remove_request (struct requestlist *last, struct requestlist *req, > + int all) > +{ > + assert (req->running == yes || req->running == queued > + || req->running == done); > + > + 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; > + } > + } > + } > +} > + > + > +/* The thread handler. */ > +static void *handle_fildes_io (void *arg); > + > + > +/* 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; > + assert (powerof2 (ENTRIES_PER_ROW)); > + optim.aio_num = (init->aio_num < ENTRIES_PER_ROW > + ? ENTRIES_PER_ROW > + : init->aio_num & ~(ENTRIES_PER_ROW - 1)); > + } > + > + 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) > + > + > +/* The main function of the async I/O handling. It enqueues requests > + and if necessary starts and handles threads. */ > +struct requestlist * > +__aio_enqueue_request (aiocb_union *aiocbp, int operation) > +{ > + int result = 0; > + int policy, prio; > + struct sched_param param; > + struct requestlist *last, *runp, *newp; > + int running = no; > + > + if (operation == LIO_SYNC || operation == LIO_DSYNC) > + aiocbp->aiocb.aio_reqprio = 0; > + else if (aiocbp->aiocb.aio_reqprio < 0 > +#ifdef AIO_PRIO_DELTA_MAX > + || aiocbp->aiocb.aio_reqprio > AIO_PRIO_DELTA_MAX > +#endif > + ) > + { > + /* Invalid priority value. */ > + __set_errno (EINVAL); > + aiocbp->aiocb.__error_code = EINVAL; > + aiocbp->aiocb.__return_value = -1; > + return NULL; > + } > + > + /* 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); > + > + last = NULL; > + runp = requests; > + /* First look whether the current file descriptor is currently > + worked with. */ > + while (runp != NULL > + && runp->aiocbp->aiocb.aio_fildes < aiocbp->aiocb.aio_fildes) > + { > + last = runp; > + runp = runp->next_fd; > + } > + > + /* 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; > + newp->waiting = NULL; > + > + aiocbp->aiocb.__abs_prio = prio; > + aiocbp->aiocb.__policy = policy; > + aiocbp->aiocb.aio_lio_opcode = operation; > + aiocbp->aiocb.__error_code = EINPROGRESS; > + aiocbp->aiocb.__return_value = 0; > + > + if (runp != NULL > + && runp->aiocbp->aiocb.aio_fildes == aiocbp->aiocb.aio_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. */ > + last = NULL; > + while (runp->next_prio != NULL > + && runp->next_prio->aiocbp->aiocb.__abs_prio >= prio) > + { > + last = runp; > + runp = runp->next_prio; > + } > + > + newp->next_prio = runp->next_prio; > + runp->next_prio = newp; > + > + running = queued; > + } > + else > + { > + running = yes; > + /* Enqueue this request for a new descriptor. */ > + if (last == NULL) > + { > + newp->last_fd = NULL; > + newp->next_fd = requests; > + if (requests != NULL) > + requests->last_fd = newp; > + 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; > + last = NULL; > + } > + > + 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. */ > + result = aio_create_helper_thread (&thid, handle_fildes_io, newp); > + if (result == 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. */ > + __aio_remove_request (last, newp, 0); > + } > + else > + result = 0; > + } > + } > + } > + > + /* 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; > + else > + { > + /* Something went wrong. */ > + __aio_free_request (newp); > + aiocbp->aiocb.__error_code = result; > + __set_errno (result); > + newp = NULL; > + } > + > + /* Release the mutex. */ > + pthread_mutex_unlock (&__aio_requests_mutex); > + > + return newp; > +} > + > + > +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 (sizeof (off_t) != sizeof (off64_t) > + && 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 (__libc_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 (sizeof (off_t) != sizeof (off64_t) > + && 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.__return_value = > + TEMP_FAILURE_RETRY (fdatasync (fildes)); > + else if (aiocbp->aiocb.aio_lio_opcode == LIO_SYNC) > + 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); > + > + 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 timespec now; > + struct timespec wakeup_time; > + > + ++idle_thread_count; > + __clock_gettime (CLOCK_REALTIME, &now); > + wakeup_time.tv_sec = now.tv_sec + optim.aio_idle_time; > + wakeup_time.tv_nsec = now.tv_nsec; > + 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; > + pthread_attr_t attr; > + > + /* Make sure the thread is created detached. */ > + pthread_attr_init (&attr); > + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); > + > + /* 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 (pthread_create (&thid, &attr, 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 > +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; > + } > +} Ok. > diff --git a/rt/aio_notify.c b/rt/aio_notify.c > index 9d51fd9c5e..a8d61503d8 100644 > --- a/rt/aio_notify.c > +++ b/rt/aio_notify.c > @@ -1,6 +1,7 @@ > -/* Notify initiator of AIO request. Stub version. > - Copyright (C) 2001-2021 Free Software Foundation, Inc. > +/* Notify initiator of AIO request. > + Copyright (C) 1997-2021 Free Software Foundation, Inc. > This file is part of the GNU C Library. > + Contributed by Ulrich Drepper , 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 > @@ -16,8 +17,141 @@ > License along with the GNU C Library; if not, see > . */ > > -#include > +#include > +#include > +#include > +#include > #include > +#include > > -/* This file contains only internal functions used by > - the particular aio_* implementation code. */ > +#ifndef aio_start_notify_thread > +# define aio_start_notify_thread() do { } while (0) > +#endif > + > +struct notify_func > + { > + void (*func) (sigval_t); > + sigval_t value; > + }; > + > +static void * > +notify_func_wrapper (void *arg) > +{ > + aio_start_notify_thread (); > + struct notify_func *const n = arg; > + void (*func) (sigval_t) = n->func; > + sigval_t value = n->value; > + free (n); > + (*func) (value); > + return NULL; > +} > + > + > +int > +__aio_notify_only (struct sigevent *sigev) > +{ > + int result = 0; > + > + /* Send the signal to notify about finished processing of the request. */ > + if (__glibc_unlikely (sigev->sigev_notify == SIGEV_THREAD)) > + { > + /* We have to start a thread. */ > + pthread_t tid; > + pthread_attr_t attr, *pattr; > + > + pattr = (pthread_attr_t *) sigev->sigev_notify_attributes; > + if (pattr == NULL) > + { > + pthread_attr_init (&attr); > + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); > + pattr = &attr; > + } > + > + /* SIGEV may be freed as soon as we return, so we cannot let the > + notification thread use that pointer. Even though a sigval_t is > + only one word and the same size as a void *, we cannot just pass > + the value through pthread_create as the argument and have the new > + thread run the user's function directly, because on some machines > + the calling convention for a union like sigval_t is different from > + that for a pointer type like void *. */ > + struct notify_func *nf = malloc (sizeof *nf); > + if (nf == NULL) > + result = -1; > + else > + { > + nf->func = sigev->sigev_notify_function; > + nf->value = sigev->sigev_value; > + if (pthread_create (&tid, pattr, notify_func_wrapper, nf) < 0) > + { > + free (nf); > + result = -1; > + } > + } > + } > + else if (sigev->sigev_notify == SIGEV_SIGNAL) > + { > + /* We have to send a signal. */ > +#if _POSIX_REALTIME_SIGNALS > 0 > + /* Note that the standard gives us the option of using a plain > + non-queuing signal here when SA_SIGINFO is not set for the signal. */ > + if (__aio_sigqueue (sigev->sigev_signo, sigev->sigev_value, getpid ()) > + < 0) > + result = -1; > +#else > + /* There are no queued signals on this system at all. */ > + result = raise (sigev->sigev_signo); > +#endif > + } > + > + return result; > +} > + > + > +void > +__aio_notify (struct requestlist *req) > +{ > + struct waitlist *waitlist; > + struct aiocb *aiocbp = &req->aiocbp->aiocb; > + > + if (__aio_notify_only (&aiocbp->aio_sigevent) != 0) > + { > + /* XXX What shall we do if already an error is set by > + read/write/fsync? */ > + aiocbp->__error_code = errno; > + aiocbp->__return_value = -1; > + } > + > + /* Now also notify possibly waiting threads. */ > + waitlist = req->waiting; > + while (waitlist != NULL) > + { > + struct waitlist *next = waitlist->next; > + > + if (waitlist->sigevp == NULL) > + { > + if (waitlist->result != NULL && aiocbp->__return_value == -1) > + *waitlist->result = -1; > + > +#ifdef DONT_NEED_AIO_MISC_COND > + AIO_MISC_NOTIFY (waitlist); > +#else > + /* Decrement the counter. */ > + --*waitlist->counterp; > + > + pthread_cond_signal (waitlist->cond); > +#endif > + } > + else > + /* This is part of an asynchronous `lio_listio' operation. If > + this request is the last one, send the signal. */ > + if (--*waitlist->counterp == 0) > + { > + __aio_notify_only (waitlist->sigevp); > + /* This is tricky. See lio_listio.c for the reason why > + this works. */ > + free ((void *) waitlist->counterp); > + } > + > + waitlist = next; > + } > +} > diff --git a/rt/aio_read.c b/rt/aio_read.c > index fcd5acea8e..4698e48b1c 100644 > --- a/rt/aio_read.c > +++ b/rt/aio_read.c > @@ -1,6 +1,7 @@ > -/* Asynchronous read. Stub version. > - Copyright (C) 2001-2021 Free Software Foundation, Inc. > +/* Asynchronous read. > + Copyright (C) 1997-2021 Free Software Foundation, Inc. > This file is part of the GNU C Library. > + Contributed by Ulrich Drepper , 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 > @@ -17,18 +18,13 @@ > . */ > > #include > -#include > > -#ifdef BE_AIO64 > -#define aiocb aiocb64 > -#define aio_read aio_read64 > -#endif > +#include > + > > int > aio_read (struct aiocb *aiocbp) > { > - __set_errno (ENOSYS); > - return -1; > + return (__aio_enqueue_request ((aiocb_union *) aiocbp, LIO_READ) == NULL > + ? -1 : 0); > } > - > -stub_warning (aio_read) Ok. > diff --git a/rt/aio_read64.c b/rt/aio_read64.c > index e9994aefcb..26b9b0b380 100644 > --- a/rt/aio_read64.c > +++ b/rt/aio_read64.c > @@ -1,2 +1,30 @@ > -#define BE_AIO64 > -#include > +/* Asynchronous read, 64bit offset version. > + Copyright (C) 1997-2021 Free Software Foundation, Inc. > + This file is part of the GNU C Library. > + Contributed by Ulrich Drepper , 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, see > + . */ > + > +#include > + > +#include > + > + > +int > +aio_read64 (struct aiocb64 *aiocbp) > +{ > + return (__aio_enqueue_request ((aiocb_union *) aiocbp, LIO_READ64) == NULL > + ? -1 : 0); > +} Ok. > diff --git a/rt/aio_suspend.c b/rt/aio_suspend.c > index 32f5f7e742..6fd5b1bee2 100644 > --- a/rt/aio_suspend.c > +++ b/rt/aio_suspend.c > @@ -1,6 +1,7 @@ > -/* Suspend until termination of a requests. Stub version. > - Copyright (C) 2001-2021 Free Software Foundation, Inc. > +/* Suspend until termination of a requests. > + Copyright (C) 1997-2021 Free Software Foundation, Inc. > This file is part of the GNU C Library. > + Contributed by Ulrich Drepper , 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 > @@ -27,18 +28,236 @@ > /* And undo the hack. */ > #undef aio_suspend64 > > +#include > #include > +#include > +#include > #include > > +#include > +#include > + > + > +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); > +} > + > +#ifdef DONT_NEED_AIO_MISC_COND > +static int > +__attribute__ ((noinline)) > +do_aio_misc_wait (unsigned int *cntr, const struct __timespec64 *timeout) > +{ > + int result = 0; > + > + AIO_MISC_WAIT (result, *cntr, timeout, 1); > + > + return result; > +} > +#endif > > int > -aio_suspend (const struct aiocb *const list[], int nent, > - const struct timespec *timeout) > +__aio_suspend_time64 (const struct aiocb *const list[], int nent, > + const struct __timespec64 *timeout) > { > - __set_errno (ENOSYS); > - return -1; > + if (__glibc_unlikely (nent < 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; > + bool any = false; > + int result = 0; > + unsigned int cntr = 1; > + > + /* 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; > + requestlist[cnt]->waiting = &waitlist[cnt]; > + any = true; > + } > + else > + /* We will never suspend. */ > + break; > + } > + else > + /* We will never suspend. */ > + break; > + } > + > + struct __timespec64 ts; > + if (timeout != NULL) > + { > + __clock_gettime64 (CLOCK_MONOTONIC, &ts); > + ts.tv_sec += timeout->tv_sec; > + ts.tv_nsec += timeout->tv_nsec; > + if (ts.tv_nsec >= 1000000000) > + { > + ts.tv_nsec -= 1000000000; > + ts.tv_sec++; > + } > + } > + > + /* Only if none of the entries is NULL or finished to be wait. */ > + if (cnt == nent && any) > + { > + 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); > + > +#ifdef DONT_NEED_AIO_MISC_COND > + result = do_aio_misc_wait (&cntr, timeout == NULL ? NULL : &ts); > +#else > + struct timespec ts32 = valid_timespec64_to_timespec (ts); > + result = pthread_cond_timedwait (&cond, &__aio_requests_mutex, > + timeout == NULL ? NULL : &ts32); > +#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 (__glibc_unlikely (pthread_cond_destroy (&cond) != 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) > > -stub_warning (aio_suspend) > -stub_warning (aio_suspend64) > +#if __TIMESIZE != 64 > +librt_hidden_def (__aio_suspend_time64) > + > +int > +__aio_suspend (const struct aiocb *const list[], int nent, > + const struct timespec *timeout) > +{ > + struct __timespec64 ts64; > + > + if (timeout != NULL) > + ts64 = valid_timespec_to_timespec64 (*timeout); > + > + return __aio_suspend_time64 (list, nent, timeout != NULL ? &ts64 : NULL); > +} > +#endif > +weak_alias (__aio_suspend, aio_suspend) > +weak_alias (aio_suspend, aio_suspend64) Ok. > diff --git a/rt/aio_write.c b/rt/aio_write.c > index 18a338e094..ea55f0dbbc 100644 > --- a/rt/aio_write.c > +++ b/rt/aio_write.c > @@ -1,6 +1,7 @@ > -/* Asynchronous write. Stub version. > - Copyright (C) 2001-2021 Free Software Foundation, Inc. > +/* Asynchronous write. > + Copyright (C) 1997-2021 Free Software Foundation, Inc. > This file is part of the GNU C Library. > + Contributed by Ulrich Drepper , 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 > @@ -17,18 +18,13 @@ > . */ > > #include > -#include > > -#ifdef BE_AIO64 > -#define aiocb aiocb64 > -#define aio_write aio_write64 > -#endif > +#include > + > > int > aio_write (struct aiocb *aiocbp) > { > - __set_errno (ENOSYS); > - return -1; > + return (__aio_enqueue_request ((aiocb_union *) aiocbp, LIO_WRITE) == NULL > + ? -1 : 0); > } > - > -stub_warning (aio_write) Ok. > diff --git a/rt/aio_write64.c b/rt/aio_write64.c > index 88d5c001ce..bd6dd316be 100644 > --- a/rt/aio_write64.c > +++ b/rt/aio_write64.c > @@ -1,2 +1,30 @@ > -#define BE_AIO64 > -#include > +/* Asynchronous write, 64bit offset version. > + Copyright (C) 1997-2021 Free Software Foundation, Inc. > + This file is part of the GNU C Library. > + Contributed by Ulrich Drepper , 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, see > + . */ > + > +#include > + > +#include > + > + > +int > +aio_write64 (struct aiocb64 *aiocbp) > +{ > + return (__aio_enqueue_request ((aiocb_union *) aiocbp, LIO_WRITE64) == NULL > + ? -1 : 0); > +} Ok. > diff --git a/rt/lio_listio.c b/rt/lio_listio.c > index db4ce68afc..2cab3c2254 100644 > --- a/rt/lio_listio.c > +++ b/rt/lio_listio.c > @@ -1,6 +1,7 @@ > -/* Enqueue a list of read or write requests. Stub version. > - Copyright (C) 2001-2021 Free Software Foundation, Inc. > +/* Enqueue and list of read or write requests. > + Copyright (C) 1997-2021 Free Software Foundation, Inc. > This file is part of the GNU C Library. > + Contributed by Ulrich Drepper , 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 > @@ -16,25 +17,232 @@ > License along with the GNU C Library; if not, see > . */ > > +#ifndef lio_listio > #include > +#include > #include > +#include > +#include > > -#ifdef BE_AIO64 > -#define lio_listio lio_listio64 > -#define aiocb aiocb64 > -#define aio_read aio_read64 > -#define aio_write aio_write64 > -#define aio_suspend aio_suspend64 > +#include > + > +#define LIO_OPCODE_BASE 0 > +#endif > + > +#include > + > + > +/* We need this special structure to handle asynchronous I/O. */ > +struct async_waitlist > + { > + unsigned 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 unsigned int total = 0; > + int result = 0; > + > + if (sig == NULL) > + { > + defsigev.sigev_notify = SIGEV_NONE; > + sig = &defsigev; > + } > + > + /* Request the mutex. */ > + pthread_mutex_lock (&__aio_requests_mutex); > + > + /* 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 ((aiocb_union *) list[cnt], > + (list[cnt]->aio_lio_opcode > + | LIO_OPCODE_BASE)); > + > + 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. */ > + > + /* 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) > + __aio_notify_only (sig); > + > + 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]; > + > + 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[cnt].cond = &cond; > #endif > + waitlist[cnt].result = &result; > + waitlist[cnt].next = requests[cnt]->waiting; > + waitlist[cnt].counterp = &total; > + waitlist[cnt].sigevp = NULL; > + requests[cnt]->waiting = &waitlist[cnt]; > + ++total; > + } > + } > > +#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 any of the I/O requests failed, return -1 and set errno. */ > + if (result != 0) > + { > + __set_errno (result == EINTR ? EINTR : EIO); > + result = -1; > + } > + } > + else > + { > + 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 > + { > + 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; > + 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 > -lio_listio (int mode, > - struct aiocb *const list[], int nent, > - struct sigevent *sig) > +attribute_compat_text_section > +__lio_listio_21 (int mode, struct aiocb *const list[], int nent, > + struct sigevent *sig) > { > - __set_errno (ENOSYS); > - return -1; > + /* 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 > > -stub_warning (lio_listio) > + > +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); Ok. > diff --git a/rt/lio_listio64.c b/rt/lio_listio64.c > index 35a571c685..111c883a2f 100644 > --- a/rt/lio_listio64.c > +++ b/rt/lio_listio64.c > @@ -1,2 +1,33 @@ > -#define BE_AIO64 > +/* Enqueue and list of read or write requests, 64bit offset version. > + Copyright (C) 1997-2021 Free Software Foundation, Inc. > + This file is part of the GNU C Library. > + Contributed by Ulrich Drepper , 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, see > + . */ > + > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#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 > diff --git a/rt/timer_create.c b/rt/timer_create.c > index 79d4d18317..2808f5b32b 100644 > --- a/rt/timer_create.c > +++ b/rt/timer_create.c > @@ -1,10 +1,11 @@ > -/* Copyright (C) 1999-2021 Free Software Foundation, Inc. > +/* Copyright (C) 2000-2021 Free Software Foundation, Inc. > This file is part of the GNU C Library. > + Contributed by Kaz Kylheku . > > 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. > + 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 > @@ -12,17 +13,154 @@ > 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, see > - . */ > + License along with the GNU C Library; see the file COPYING.LIB. If > + not, see . */ > > #include > +#include > +#include > #include > +#include > + > +#include "posix-timer.h" > + > > /* Create new per-process timer using CLOCK. */ > int > timer_create (clockid_t clock_id, struct sigevent *evp, timer_t *timerid) > { > - __set_errno (ENOSYS); > - return -1; > + int retval = -1; > + struct timer_node *newtimer = NULL; > + struct thread_node *thread = NULL; > + > + if (0 > +#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0 > + || clock_id == CLOCK_PROCESS_CPUTIME_ID > +#endif > +#if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0 > + || clock_id == CLOCK_THREAD_CPUTIME_ID > +#endif > + ) > + { > + /* We don't allow timers for CPU clocks. At least not in the > + moment. */ > + __set_errno (ENOTSUP); > + return -1; > + } > + > + if (clock_id != CLOCK_REALTIME) > + { > + __set_errno (EINVAL); > + return -1; > + } > + > + pthread_once (&__timer_init_once_control, __timer_init_once); > + > + if (__timer_init_failed) > + { > + __set_errno (ENOMEM); > + return -1; > + } > + > + pthread_mutex_lock (&__timer_mutex); > + > + newtimer = __timer_alloc (); > + if (__glibc_unlikely (newtimer == NULL)) > + { > + __set_errno (EAGAIN); > + goto unlock_bail; > + } > + > + if (evp != NULL) > + newtimer->event = *evp; > + else > + { > + newtimer->event.sigev_notify = SIGEV_SIGNAL; > + newtimer->event.sigev_signo = SIGALRM; > + newtimer->event.sigev_value.sival_ptr = newtimer; > + newtimer->event.sigev_notify_function = 0; > + } > + > + newtimer->event.sigev_notify_attributes = &newtimer->attr; > + newtimer->creator_pid = getpid (); > + > + switch (__builtin_expect (newtimer->event.sigev_notify, SIGEV_SIGNAL)) > + { > + case SIGEV_NONE: > + case SIGEV_SIGNAL: > + /* We have a global thread for delivering timed signals. > + If it is not running, try to start it up. */ > + thread = &__timer_signal_thread_rclk; > + if (! thread->exists) > + { > + if (__builtin_expect (__timer_thread_start (thread), > + 1) < 0) > + { > + __set_errno (EAGAIN); > + goto unlock_bail; > + } > + } > + break; > + > + case SIGEV_THREAD: > + /* Copy over thread attributes or set up default ones. */ > + if (evp->sigev_notify_attributes) > + newtimer->attr = *(pthread_attr_t *) evp->sigev_notify_attributes; > + else > + pthread_attr_init (&newtimer->attr); > + > + /* Ensure thread attributes call for deatched thread. */ > + pthread_attr_setdetachstate (&newtimer->attr, PTHREAD_CREATE_DETACHED); > + > + /* Try to find existing thread having the right attributes. */ > + thread = __timer_thread_find_matching (&newtimer->attr, clock_id); > + > + /* If no existing thread has these attributes, try to allocate one. */ > + if (thread == NULL) > + thread = __timer_thread_alloc (&newtimer->attr, clock_id); > + > + /* Out of luck; no threads are available. */ > + if (__glibc_unlikely (thread == NULL)) > + { > + __set_errno (EAGAIN); > + goto unlock_bail; > + } > + > + /* If the thread is not running already, try to start it. */ > + if (! thread->exists > + && __builtin_expect (! __timer_thread_start (thread), 0)) > + { > + __set_errno (EAGAIN); > + goto unlock_bail; > + } > + break; > + > + default: > + __set_errno (EINVAL); > + goto unlock_bail; > + } > + > + newtimer->clock = clock_id; > + newtimer->abstime = 0; > + newtimer->armed = 0; > + newtimer->thread = thread; > + > + *timerid = timer_ptr2id (newtimer); > + retval = 0; > + > + if (__builtin_expect (retval, 0) == -1) > + { > + unlock_bail: > + if (thread != NULL) > + __timer_thread_dealloc (thread); > + if (newtimer != NULL) > + { > + timer_delref (newtimer); > + __timer_dealloc (newtimer); > + } > + } > + > + pthread_mutex_unlock (&__timer_mutex); > + > + return retval; > } > -stub_warning (timer_create) Ok. > diff --git a/rt/timer_delete.c b/rt/timer_delete.c > index 71da429e8b..c6f6d9743d 100644 > --- a/rt/timer_delete.c > +++ b/rt/timer_delete.c > @@ -1,10 +1,11 @@ > -/* Copyright (C) 1999-2021 Free Software Foundation, Inc. > +/* Copyright (C) 2000-2021 Free Software Foundation, Inc. > This file is part of the GNU C Library. > + Contributed by Kaz Kylheku . > > 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. > + 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 > @@ -12,17 +13,56 @@ > 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, see > - . */ > + License along with the GNU C Library; see the file COPYING.LIB. If > + not, see . */ > > +#include > #include > +#include > #include > > +#include "posix-timer.h" > + > + > /* Delete timer TIMERID. */ > int > timer_delete (timer_t timerid) > { > - __set_errno (ENOSYS); > - return -1; > + struct timer_node *timer; > + int retval = -1; > + > + pthread_mutex_lock (&__timer_mutex); > + > + timer = timer_id2ptr (timerid); > + if (! timer_valid (timer)) > + /* Invalid timer ID or the timer is not in use. */ > + __set_errno (EINVAL); > + else > + { > + if (timer->armed && timer->thread != NULL) > + { > + struct thread_node *thread = timer->thread; > + assert (thread != NULL); > + > + /* If thread is cancelled while waiting for handler to terminate, > + the mutex is unlocked and timer_delete is aborted. */ > + pthread_cleanup_push (__timer_mutex_cancel_handler, &__timer_mutex); > + > + /* If timer is currently being serviced, wait for it to finish. */ > + while (thread->current_timer == timer) > + pthread_cond_wait (&thread->cond, &__timer_mutex); > + > + pthread_cleanup_pop (0); > + } > + > + /* Remove timer from whatever queue it may be on and deallocate it. */ > + timer->inuse = TIMER_DELETED; > + list_unlink_ip (&timer->links); > + timer_delref (timer); > + retval = 0; > + } > + > + pthread_mutex_unlock (&__timer_mutex); > + > + return retval; > } > -stub_warning (timer_delete) Ok. > diff --git a/rt/timer_getoverr.c b/rt/timer_getoverr.c > index 3680ba687f..c1952f80c6 100644 > --- a/rt/timer_getoverr.c > +++ b/rt/timer_getoverr.c > @@ -1,10 +1,11 @@ > -/* Copyright (C) 1999-2021 Free Software Foundation, Inc. > +/* Copyright (C) 2000-2021 Free Software Foundation, Inc. > This file is part of the GNU C Library. > + Contributed by Kaz Kylheku . > > 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. > + 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 > @@ -12,17 +13,31 @@ > 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, see > - . */ > + License along with the GNU C Library; see the file COPYING.LIB. If > + not, see . */ > > #include > +#include > #include > > +#include "posix-timer.h" > + > + > /* Get expiration overrun for timer TIMERID. */ > int > timer_getoverrun (timer_t timerid) > { > - __set_errno (ENOSYS); > - return -1; > + struct timer_node *timer; > + int retval = -1; > + > + pthread_mutex_lock (&__timer_mutex); > + > + if (! timer_valid (timer = timer_id2ptr (timerid))) > + __set_errno (EINVAL); > + else > + retval = timer->overrun_count; > + > + pthread_mutex_unlock (&__timer_mutex); > + > + return retval; > } > -stub_warning (timer_getoverrun) Ok. > diff --git a/rt/timer_gettime.c b/rt/timer_gettime.c > index 7bd94386a4..dd3b4a6281 100644 > --- a/rt/timer_gettime.c > +++ b/rt/timer_gettime.c > @@ -1,10 +1,11 @@ > -/* Copyright (C) 1999-2021 Free Software Foundation, Inc. > +/* Copyright (C) 2000-2021 Free Software Foundation, Inc. > This file is part of the GNU C Library. > + Contributed by Kaz Kylheku . > > 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. > + 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 > @@ -12,17 +13,62 @@ > 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, see > - . */ > + License along with the GNU C Library; see the file COPYING.LIB. If > + not, see . */ > > #include > +#include > #include > > +#include "posix-timer.h" > + > + > /* Get current value of timer TIMERID and store it in VLAUE. */ > int > timer_gettime (timer_t timerid, struct itimerspec *value) > { > - __set_errno (ENOSYS); > - return -1; > + struct timer_node *timer; > + struct timespec now, expiry; > + int retval = -1, armed = 0, valid; > + clock_t clock = 0; > + > + pthread_mutex_lock (&__timer_mutex); > + > + timer = timer_id2ptr (timerid); > + valid = timer_valid (timer); > + > + if (valid) { > + armed = timer->armed; > + expiry = timer->expirytime; > + clock = timer->clock; > + value->it_interval = timer->value.it_interval; > + } > + > + pthread_mutex_unlock (&__timer_mutex); > + > + if (valid) > + { > + if (armed) > + { > + __clock_gettime (clock, &now); > + if (timespec_compare (&now, &expiry) < 0) > + timespec_sub (&value->it_value, &expiry, &now); > + else > + { > + value->it_value.tv_sec = 0; > + value->it_value.tv_nsec = 0; > + } > + } > + else > + { > + value->it_value.tv_sec = 0; > + value->it_value.tv_nsec = 0; > + } > + > + retval = 0; > + } > + else > + __set_errno (EINVAL); > + > + return retval; > } > -stub_warning (timer_gettime) Ok. > diff --git a/rt/timer_settime.c b/rt/timer_settime.c > index cde0e742fc..c05adf166f 100644 > --- a/rt/timer_settime.c > +++ b/rt/timer_settime.c > @@ -1,10 +1,11 @@ > -/* Copyright (C) 1999-2021 Free Software Foundation, Inc. > +/* Copyright (C) 2000-2021 Free Software Foundation, Inc. > This file is part of the GNU C Library. > + Contributed by Kaz Kylheku . > > 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. > + 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 > @@ -12,18 +13,119 @@ > 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, see > - . */ > + License along with the GNU C Library; see the file COPYING.LIB. If > + not, see . */ > > #include > +#include > #include > > +#include "posix-timer.h" > + > + > /* Set timer TIMERID to VALUE, returning old value in OVLAUE. */ > int > timer_settime (timer_t timerid, int flags, const struct itimerspec *value, > struct itimerspec *ovalue) > { > - __set_errno (ENOSYS); > - return -1; > + struct timer_node *timer; > + struct thread_node *thread = NULL; > + struct timespec now; > + int have_now = 0, need_wakeup = 0; > + int retval = -1; > + > + timer = timer_id2ptr (timerid); > + if (timer == NULL) > + { > + __set_errno (EINVAL); > + goto bail; > + } > + > + if (! valid_nanoseconds (value->it_interval.tv_nsec) > + || ! valid_nanoseconds (value->it_value.tv_nsec)) > + { > + __set_errno (EINVAL); > + goto bail; > + } > + > + /* Will need to know current time since this is a relative timer; > + might as well make the system call outside of the lock now! */ > + > + if ((flags & TIMER_ABSTIME) == 0) > + { > + __clock_gettime (timer->clock, &now); > + have_now = 1; > + } > + > + pthread_mutex_lock (&__timer_mutex); > + timer_addref (timer); > + > + /* One final check of timer validity; this one is possible only > + until we have the mutex, because it accesses the inuse flag. */ > + > + if (! timer_valid(timer)) > + { > + __set_errno (EINVAL); > + goto unlock_bail; > + } > + > + if (ovalue != NULL) > + { > + ovalue->it_interval = timer->value.it_interval; > + > + if (timer->armed) > + { > + if (! have_now) > + { > + pthread_mutex_unlock (&__timer_mutex); > + __clock_gettime (timer->clock, &now); > + have_now = 1; > + pthread_mutex_lock (&__timer_mutex); > + timer_addref (timer); > + } > + > + timespec_sub (&ovalue->it_value, &timer->expirytime, &now); > + } > + else > + { > + ovalue->it_value.tv_sec = 0; > + ovalue->it_value.tv_nsec = 0; > + } > + } > + > + timer->value = *value; > + > + list_unlink_ip (&timer->links); > + timer->armed = 0; > + > + thread = timer->thread; > + > + /* A value of { 0, 0 } causes the timer to be stopped. */ > + if (value->it_value.tv_sec != 0 > + || __builtin_expect (value->it_value.tv_nsec != 0, 1)) > + { > + if ((flags & TIMER_ABSTIME) != 0) > + /* The user specified the expiration time. */ > + timer->expirytime = value->it_value; > + else > + timespec_add (&timer->expirytime, &now, &value->it_value); > + > + /* Only need to wake up the thread if timer is inserted > + at the head of the queue. */ > + if (thread != NULL) > + need_wakeup = __timer_thread_queue_timer (thread, timer); > + timer->armed = 1; > + } > + > + retval = 0; > + > +unlock_bail: > + timer_delref (timer); > + pthread_mutex_unlock (&__timer_mutex); > + > +bail: > + if (thread != NULL && need_wakeup) > + __timer_thread_wakeup (thread); > + > + return retval; > } > -stub_warning (timer_settime) Ok. > diff --git a/sysdeps/generic/aio_misc.h b/sysdeps/generic/aio_misc.h > index 1307d822a0..e23524cffe 100644 > --- a/sysdeps/generic/aio_misc.h > +++ b/sysdeps/generic/aio_misc.h > @@ -1,5 +1,4 @@ > -/* Internal declarations for functions implementation. Stub version. > - Copyright (C) 2001-2021 Free Software Foundation, Inc. > +/* Copyright (C) 1997-2021 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 > @@ -20,17 +19,19 @@ > #define _AIO_MISC_H 1 > > #include > +#include > > > /* Extend the operation enum. */ > enum > { > - LIO_DSYNC = LIO_READ + 1, > + LIO_DSYNC = LIO_NOP + 1, > LIO_SYNC, > LIO_READ64 = LIO_READ | 128, > LIO_WRITE64 = LIO_WRITE | 128 > }; > > + > /* Union of the two request types. */ > typedef union > { > @@ -39,9 +40,83 @@ typedef union > } aiocb_union; > > > +/* Used to synchronize. */ > +struct waitlist > + { > + struct waitlist *next; > + > + /* The next two fields is used in synchronous `lio_listio' operations. */ > +#ifndef DONT_NEED_AIO_MISC_COND > + pthread_cond_t *cond; > +#endif > + int *result; > + > + volatile unsigned int *counterp; > + /* The next field is used in asynchronous `lio_listio' operations. */ > + struct sigevent *sigevp; > + }; > + > + > +/* Status of a request. */ > +enum > +{ > + no, > + queued, > + yes, > + allocated, > + done > +}; > + > + > +/* Used to queue requests.. */ > +struct requestlist > + { > + int running; > + > + struct requestlist *last_fd; > + struct requestlist *next_fd; > + struct requestlist *next_prio; > + struct requestlist *next_run; > + > + /* Pointer to the actual data. */ > + aiocb_union *aiocbp; > + > + /* 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 (aiocb_union *aiocbp, > + int operation) > + attribute_hidden; > + > +/* Find request entry for given AIO control block. */ > +extern struct requestlist *__aio_find_req (aiocb_union *elem) attribute_hidden; > + > +/* Find request entry for given file descriptor. */ > +extern struct requestlist *__aio_find_req_fd (int fildes) attribute_hidden; > + > +/* Remove request from the list. */ > +extern void __aio_remove_request (struct requestlist *last, > + struct requestlist *req, int all) > + attribute_hidden; > + > +/* Release the entry for the request. */ > +extern void __aio_free_request (struct requestlist *req) attribute_hidden; > + > +/* Notify initiator of request and tell this everybody listening. */ > +extern void __aio_notify (struct requestlist *req) attribute_hidden; > + > +/* Notify initiator of request. */ > +extern int __aio_notify_only (struct sigevent *sigev) attribute_hidden; > + > /* Send the signal. */ > extern int __aio_sigqueue (int sig, const union sigval val, pid_t caller_pid) > attribute_hidden; > > - > #endif /* aio_misc.h */ Ok. > diff --git a/sysdeps/pthread/timer_routines.c b/sysdeps/htl/timer_routines.c > similarity index 100% > rename from sysdeps/pthread/timer_routines.c > rename to sysdeps/htl/timer_routines.c > diff --git a/sysdeps/pthread/Versions b/sysdeps/pthread/Versions > deleted file mode 100644 > index a71cffbed4..0000000000 > --- a/sysdeps/pthread/Versions > +++ /dev/null > @@ -1,5 +0,0 @@ > -librt { > - GLIBC_2.4 { > - lio_listio; lio_listio64; > - } > -} Ok. > diff --git a/sysdeps/pthread/aio_cancel.c b/sysdeps/pthread/aio_cancel.c > deleted file mode 100644 > index 63fd88f36c..0000000000 > --- a/sysdeps/pthread/aio_cancel.c > +++ /dev/null > @@ -1,157 +0,0 @@ > -/* Cancel requests associated with given file descriptor. > - Copyright (C) 1997-2021 Free Software Foundation, Inc. > - This file is part of the GNU C Library. > - Contributed by Ulrich Drepper , 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, see > - . */ > - > - > -/* 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 > -/* And undo the hack. */ > -#undef aio_cancel64 > -#endif > - > -#include > -#include > -#include > - > -#include > - > - > -int > -aio_cancel (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) > - { > - not_found: > - pthread_mutex_unlock (&__aio_requests_mutex); > - __set_errno (EINVAL); > - return -1; > - } > - > - while (req->aiocbp != (aiocb_union *) aiocbp) > - { > - last = req; > - req = req->next_prio; > - if (req == NULL) > - goto not_found; > - } > - > - /* 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 > - { > - /* 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); > - } > - } > - } > - > - /* 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 Ok. > diff --git a/sysdeps/pthread/aio_error.c b/sysdeps/pthread/aio_error.c > deleted file mode 100644 > index ed664ae0ef..0000000000 > --- a/sysdeps/pthread/aio_error.c > +++ /dev/null > @@ -1,48 +0,0 @@ > -/* Return error status of asynchronous I/O request. > - Copyright (C) 1997-2021 Free Software Foundation, Inc. > - This file is part of the GNU C Library. > - Contributed by Ulrich Drepper , 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, see > - . */ > - > - > -/* 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 > -/* And undo the hack. */ > -#undef aio_error64 > - > -#include > - > - > -int > -aio_error (const struct aiocb *aiocbp) > -{ > - int ret; > - > - /* Acquire the mutex to make sure all operations for this request are > - complete. */ > - pthread_mutex_lock(&__aio_requests_mutex); > - ret = aiocbp->__error_code; > - pthread_mutex_unlock(&__aio_requests_mutex); > - > - return ret; > -} > - > -weak_alias (aio_error, aio_error64) Ok. > diff --git a/sysdeps/pthread/aio_fsync.c b/sysdeps/pthread/aio_fsync.c > deleted file mode 100644 > index 5a52e2fec0..0000000000 > --- a/sysdeps/pthread/aio_fsync.c > +++ /dev/null > @@ -1,57 +0,0 @@ > -/* Synchronize I/O in given file descriptor. > - Copyright (C) 1997-2021 Free Software Foundation, Inc. > - This file is part of the GNU C Library. > - Contributed by Ulrich Drepper , 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, see > - . */ > - > - > -/* We use an UGLY hack to prevent gcc from finding us cheating. The > - implementation of aio_fsync and aio_fsync64 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_fsync64 has no prototype. */ > -#define aio_fsync64 XXX > -#include > -/* And undo the hack. */ > -#undef aio_fsync64 > -#include > -#include > - > -#include > - > - > -int > -aio_fsync (int op, struct aiocb *aiocbp) > -{ > - if (op != O_DSYNC && __builtin_expect (op != O_SYNC, 0)) > - { > - __set_errno (EINVAL); > - return -1; > - } > - > - /* Verify that this is an open file descriptor. */ > - if (__glibc_unlikely (fcntl (aiocbp->aio_fildes, F_GETFL) == -1)) > - { > - __set_errno (EBADF); > - return -1; > - } > - > - return (__aio_enqueue_request ((aiocb_union *) aiocbp, > - op == O_SYNC ? LIO_SYNC : LIO_DSYNC) == NULL > - ? -1 : 0); > -} > - > -weak_alias (aio_fsync, aio_fsync64) Ok. > diff --git a/sysdeps/pthread/aio_misc.c b/sysdeps/pthread/aio_misc.c > deleted file mode 100644 > index b95f07d9d3..0000000000 > --- a/sysdeps/pthread/aio_misc.c > +++ /dev/null > @@ -1,721 +0,0 @@ > -/* Handle general operations. > - Copyright (C) 1997-2021 Free Software Foundation, Inc. > - This file is part of the GNU C Library. > - Contributed by Ulrich Drepper , 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, see > - . */ > - > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > - > -#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); > - > -/* 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; > - > -/* 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; > - > -/* 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 simultaneous 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 > -__aio_free_request (struct requestlist *elem) > -{ > - elem->running = no; > - elem->next_prio = freelist; > - freelist = elem; > -} > - > - > -struct requestlist * > -__aio_find_req (aiocb_union *elem) > -{ > - struct requestlist *runp = requests; > - int fildes = elem->aiocb.aio_fildes; > - > - 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; > - } > - > - return runp; > -} > - > - > -struct requestlist * > -__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); > -} > - > - > -void > -__aio_remove_request (struct requestlist *last, struct requestlist *req, > - int all) > -{ > - assert (req->running == yes || req->running == queued > - || req->running == done); > - > - 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; > - } > - } > - } > -} > - > - > -/* The thread handler. */ > -static void *handle_fildes_io (void *arg); > - > - > -/* 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; > - assert (powerof2 (ENTRIES_PER_ROW)); > - optim.aio_num = (init->aio_num < ENTRIES_PER_ROW > - ? ENTRIES_PER_ROW > - : init->aio_num & ~(ENTRIES_PER_ROW - 1)); > - } > - > - 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) > - > - > -/* The main function of the async I/O handling. It enqueues requests > - and if necessary starts and handles threads. */ > -struct requestlist * > -__aio_enqueue_request (aiocb_union *aiocbp, int operation) > -{ > - int result = 0; > - int policy, prio; > - struct sched_param param; > - struct requestlist *last, *runp, *newp; > - int running = no; > - > - if (operation == LIO_SYNC || operation == LIO_DSYNC) > - aiocbp->aiocb.aio_reqprio = 0; > - else if (aiocbp->aiocb.aio_reqprio < 0 > -#ifdef AIO_PRIO_DELTA_MAX > - || aiocbp->aiocb.aio_reqprio > AIO_PRIO_DELTA_MAX > -#endif > - ) > - { > - /* Invalid priority value. */ > - __set_errno (EINVAL); > - aiocbp->aiocb.__error_code = EINVAL; > - aiocbp->aiocb.__return_value = -1; > - return NULL; > - } > - > - /* 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); > - > - last = NULL; > - runp = requests; > - /* First look whether the current file descriptor is currently > - worked with. */ > - while (runp != NULL > - && runp->aiocbp->aiocb.aio_fildes < aiocbp->aiocb.aio_fildes) > - { > - last = runp; > - runp = runp->next_fd; > - } > - > - /* 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; > - newp->waiting = NULL; > - > - aiocbp->aiocb.__abs_prio = prio; > - aiocbp->aiocb.__policy = policy; > - aiocbp->aiocb.aio_lio_opcode = operation; > - aiocbp->aiocb.__error_code = EINPROGRESS; > - aiocbp->aiocb.__return_value = 0; > - > - if (runp != NULL > - && runp->aiocbp->aiocb.aio_fildes == aiocbp->aiocb.aio_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. */ > - last = NULL; > - while (runp->next_prio != NULL > - && runp->next_prio->aiocbp->aiocb.__abs_prio >= prio) > - { > - last = runp; > - runp = runp->next_prio; > - } > - > - newp->next_prio = runp->next_prio; > - runp->next_prio = newp; > - > - running = queued; > - } > - else > - { > - running = yes; > - /* Enqueue this request for a new descriptor. */ > - if (last == NULL) > - { > - newp->last_fd = NULL; > - newp->next_fd = requests; > - if (requests != NULL) > - requests->last_fd = newp; > - 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; > - last = NULL; > - } > - > - 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. */ > - result = aio_create_helper_thread (&thid, handle_fildes_io, newp); > - if (result == 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. */ > - __aio_remove_request (last, newp, 0); > - } > - else > - result = 0; > - } > - } > - } > - > - /* 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; > - else > - { > - /* Something went wrong. */ > - __aio_free_request (newp); > - aiocbp->aiocb.__error_code = result; > - __set_errno (result); > - newp = NULL; > - } > - > - /* Release the mutex. */ > - pthread_mutex_unlock (&__aio_requests_mutex); > - > - return newp; > -} > - > - > -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 (sizeof (off_t) != sizeof (off64_t) > - && 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 (__libc_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 (sizeof (off_t) != sizeof (off64_t) > - && 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.__return_value = > - TEMP_FAILURE_RETRY (fdatasync (fildes)); > - else if (aiocbp->aiocb.aio_lio_opcode == LIO_SYNC) > - 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); > - > - 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 timespec now; > - struct timespec wakeup_time; > - > - ++idle_thread_count; > - __clock_gettime (CLOCK_REALTIME, &now); > - wakeup_time.tv_sec = now.tv_sec + optim.aio_idle_time; > - wakeup_time.tv_nsec = now.tv_nsec; > - 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; > - pthread_attr_t attr; > - > - /* Make sure the thread is created detached. */ > - pthread_attr_init (&attr); > - pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); > - > - /* 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 (pthread_create (&thid, &attr, 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 > -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; > - } > -} > diff --git a/sysdeps/pthread/aio_misc.h b/sysdeps/pthread/aio_misc.h > deleted file mode 100644 > index e23524cffe..0000000000 > --- a/sysdeps/pthread/aio_misc.h > +++ /dev/null > @@ -1,122 +0,0 @@ > -/* Copyright (C) 1997-2021 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, see > - . */ > - > -#ifndef _AIO_MISC_H > -#define _AIO_MISC_H 1 > - > -#include > -#include > - > - > -/* Extend the operation enum. */ > -enum > -{ > - LIO_DSYNC = LIO_NOP + 1, > - LIO_SYNC, > - LIO_READ64 = LIO_READ | 128, > - LIO_WRITE64 = LIO_WRITE | 128 > -}; > - > - > -/* 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 `lio_listio' operations. */ > -#ifndef DONT_NEED_AIO_MISC_COND > - pthread_cond_t *cond; > -#endif > - int *result; > - > - volatile unsigned int *counterp; > - /* The next field is used in asynchronous `lio_listio' operations. */ > - struct sigevent *sigevp; > - }; > - > - > -/* Status of a request. */ > -enum > -{ > - no, > - queued, > - yes, > - allocated, > - done > -}; > - > - > -/* Used to queue requests.. */ > -struct requestlist > - { > - int running; > - > - struct requestlist *last_fd; > - struct requestlist *next_fd; > - struct requestlist *next_prio; > - struct requestlist *next_run; > - > - /* Pointer to the actual data. */ > - aiocb_union *aiocbp; > - > - /* 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 (aiocb_union *aiocbp, > - int operation) > - attribute_hidden; > - > -/* Find request entry for given AIO control block. */ > -extern struct requestlist *__aio_find_req (aiocb_union *elem) attribute_hidden; > - > -/* Find request entry for given file descriptor. */ > -extern struct requestlist *__aio_find_req_fd (int fildes) attribute_hidden; > - > -/* Remove request from the list. */ > -extern void __aio_remove_request (struct requestlist *last, > - struct requestlist *req, int all) > - attribute_hidden; > - > -/* Release the entry for the request. */ > -extern void __aio_free_request (struct requestlist *req) attribute_hidden; > - > -/* Notify initiator of request and tell this everybody listening. */ > -extern void __aio_notify (struct requestlist *req) attribute_hidden; > - > -/* Notify initiator of request. */ > -extern int __aio_notify_only (struct sigevent *sigev) attribute_hidden; > - > -/* Send the signal. */ > -extern int __aio_sigqueue (int sig, const union sigval val, pid_t caller_pid) > - attribute_hidden; > - > -#endif /* aio_misc.h */ > diff --git a/sysdeps/pthread/aio_notify.c b/sysdeps/pthread/aio_notify.c > deleted file mode 100644 > index a8d61503d8..0000000000 > --- a/sysdeps/pthread/aio_notify.c > +++ /dev/null > @@ -1,157 +0,0 @@ > -/* Notify initiator of AIO request. > - Copyright (C) 1997-2021 Free Software Foundation, Inc. > - This file is part of the GNU C Library. > - Contributed by Ulrich Drepper , 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, see > - . */ > - > -#include > -#include > -#include > -#include > -#include > -#include > - > -#ifndef aio_start_notify_thread > -# define aio_start_notify_thread() do { } while (0) > -#endif > - > -struct notify_func > - { > - void (*func) (sigval_t); > - sigval_t value; > - }; > - > -static void * > -notify_func_wrapper (void *arg) > -{ > - aio_start_notify_thread (); > - struct notify_func *const n = arg; > - void (*func) (sigval_t) = n->func; > - sigval_t value = n->value; > - free (n); > - (*func) (value); > - return NULL; > -} > - > - > -int > -__aio_notify_only (struct sigevent *sigev) > -{ > - int result = 0; > - > - /* Send the signal to notify about finished processing of the request. */ > - if (__glibc_unlikely (sigev->sigev_notify == SIGEV_THREAD)) > - { > - /* We have to start a thread. */ > - pthread_t tid; > - pthread_attr_t attr, *pattr; > - > - pattr = (pthread_attr_t *) sigev->sigev_notify_attributes; > - if (pattr == NULL) > - { > - pthread_attr_init (&attr); > - pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); > - pattr = &attr; > - } > - > - /* SIGEV may be freed as soon as we return, so we cannot let the > - notification thread use that pointer. Even though a sigval_t is > - only one word and the same size as a void *, we cannot just pass > - the value through pthread_create as the argument and have the new > - thread run the user's function directly, because on some machines > - the calling convention for a union like sigval_t is different from > - that for a pointer type like void *. */ > - struct notify_func *nf = malloc (sizeof *nf); > - if (nf == NULL) > - result = -1; > - else > - { > - nf->func = sigev->sigev_notify_function; > - nf->value = sigev->sigev_value; > - if (pthread_create (&tid, pattr, notify_func_wrapper, nf) < 0) > - { > - free (nf); > - result = -1; > - } > - } > - } > - else if (sigev->sigev_notify == SIGEV_SIGNAL) > - { > - /* We have to send a signal. */ > -#if _POSIX_REALTIME_SIGNALS > 0 > - /* Note that the standard gives us the option of using a plain > - non-queuing signal here when SA_SIGINFO is not set for the signal. */ > - if (__aio_sigqueue (sigev->sigev_signo, sigev->sigev_value, getpid ()) > - < 0) > - result = -1; > -#else > - /* There are no queued signals on this system at all. */ > - result = raise (sigev->sigev_signo); > -#endif > - } > - > - return result; > -} > - > - > -void > -__aio_notify (struct requestlist *req) > -{ > - struct waitlist *waitlist; > - struct aiocb *aiocbp = &req->aiocbp->aiocb; > - > - if (__aio_notify_only (&aiocbp->aio_sigevent) != 0) > - { > - /* XXX What shall we do if already an error is set by > - read/write/fsync? */ > - aiocbp->__error_code = errno; > - aiocbp->__return_value = -1; > - } > - > - /* Now also notify possibly waiting threads. */ > - waitlist = req->waiting; > - while (waitlist != NULL) > - { > - struct waitlist *next = waitlist->next; > - > - if (waitlist->sigevp == NULL) > - { > - if (waitlist->result != NULL && aiocbp->__return_value == -1) > - *waitlist->result = -1; > - > -#ifdef DONT_NEED_AIO_MISC_COND > - AIO_MISC_NOTIFY (waitlist); > -#else > - /* Decrement the counter. */ > - --*waitlist->counterp; > - > - pthread_cond_signal (waitlist->cond); > -#endif > - } > - else > - /* This is part of an asynchronous `lio_listio' operation. If > - this request is the last one, send the signal. */ > - if (--*waitlist->counterp == 0) > - { > - __aio_notify_only (waitlist->sigevp); > - /* This is tricky. See lio_listio.c for the reason why > - this works. */ > - free ((void *) waitlist->counterp); > - } > - > - waitlist = next; > - } > -} > diff --git a/sysdeps/pthread/aio_read.c b/sysdeps/pthread/aio_read.c > deleted file mode 100644 > index 4698e48b1c..0000000000 > --- a/sysdeps/pthread/aio_read.c > +++ /dev/null > @@ -1,30 +0,0 @@ > -/* Asynchronous read. > - Copyright (C) 1997-2021 Free Software Foundation, Inc. > - This file is part of the GNU C Library. > - Contributed by Ulrich Drepper , 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, see > - . */ > - > -#include > - > -#include > - > - > -int > -aio_read (struct aiocb *aiocbp) > -{ > - return (__aio_enqueue_request ((aiocb_union *) aiocbp, LIO_READ) == NULL > - ? -1 : 0); > -} > diff --git a/sysdeps/pthread/aio_read64.c b/sysdeps/pthread/aio_read64.c > deleted file mode 100644 > index 26b9b0b380..0000000000 > --- a/sysdeps/pthread/aio_read64.c > +++ /dev/null > @@ -1,30 +0,0 @@ > -/* Asynchronous read, 64bit offset version. > - Copyright (C) 1997-2021 Free Software Foundation, Inc. > - This file is part of the GNU C Library. > - Contributed by Ulrich Drepper , 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, see > - . */ > - > -#include > - > -#include > - > - > -int > -aio_read64 (struct aiocb64 *aiocbp) > -{ > - return (__aio_enqueue_request ((aiocb_union *) aiocbp, LIO_READ64) == NULL > - ? -1 : 0); > -} > diff --git a/sysdeps/pthread/aio_suspend.c b/sysdeps/pthread/aio_suspend.c > deleted file mode 100644 > index 6fd5b1bee2..0000000000 > --- a/sysdeps/pthread/aio_suspend.c > +++ /dev/null > @@ -1,263 +0,0 @@ > -/* Suspend until termination of a requests. > - Copyright (C) 1997-2021 Free Software Foundation, Inc. > - This file is part of the GNU C Library. > - Contributed by Ulrich Drepper , 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, see > - . */ > - > - > -/* 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 > -/* And undo the hack. */ > -#undef aio_suspend64 > - > -#include > -#include > -#include > -#include > -#include > - > -#include > -#include > - > - > -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); > -} > - > -#ifdef DONT_NEED_AIO_MISC_COND > -static int > -__attribute__ ((noinline)) > -do_aio_misc_wait (unsigned int *cntr, const struct __timespec64 *timeout) > -{ > - int result = 0; > - > - AIO_MISC_WAIT (result, *cntr, timeout, 1); > - > - return result; > -} > -#endif > - > -int > -__aio_suspend_time64 (const struct aiocb *const list[], int nent, > - const struct __timespec64 *timeout) > -{ > - if (__glibc_unlikely (nent < 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; > - bool any = false; > - int result = 0; > - unsigned int cntr = 1; > - > - /* 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; > - requestlist[cnt]->waiting = &waitlist[cnt]; > - any = true; > - } > - else > - /* We will never suspend. */ > - break; > - } > - else > - /* We will never suspend. */ > - break; > - } > - > - struct __timespec64 ts; > - if (timeout != NULL) > - { > - __clock_gettime64 (CLOCK_MONOTONIC, &ts); > - ts.tv_sec += timeout->tv_sec; > - ts.tv_nsec += timeout->tv_nsec; > - if (ts.tv_nsec >= 1000000000) > - { > - ts.tv_nsec -= 1000000000; > - ts.tv_sec++; > - } > - } > - > - /* Only if none of the entries is NULL or finished to be wait. */ > - if (cnt == nent && any) > - { > - 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); > - > -#ifdef DONT_NEED_AIO_MISC_COND > - result = do_aio_misc_wait (&cntr, timeout == NULL ? NULL : &ts); > -#else > - struct timespec ts32 = valid_timespec64_to_timespec (ts); > - result = pthread_cond_timedwait (&cond, &__aio_requests_mutex, > - timeout == NULL ? NULL : &ts32); > -#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 (__glibc_unlikely (pthread_cond_destroy (&cond) != 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; > -} > - > -#if __TIMESIZE != 64 > -librt_hidden_def (__aio_suspend_time64) > - > -int > -__aio_suspend (const struct aiocb *const list[], int nent, > - const struct timespec *timeout) > -{ > - struct __timespec64 ts64; > - > - if (timeout != NULL) > - ts64 = valid_timespec_to_timespec64 (*timeout); > - > - return __aio_suspend_time64 (list, nent, timeout != NULL ? &ts64 : NULL); > -} > -#endif > -weak_alias (__aio_suspend, aio_suspend) > -weak_alias (aio_suspend, aio_suspend64) > diff --git a/sysdeps/pthread/aio_write.c b/sysdeps/pthread/aio_write.c > deleted file mode 100644 > index ea55f0dbbc..0000000000 > --- a/sysdeps/pthread/aio_write.c > +++ /dev/null > @@ -1,30 +0,0 @@ > -/* Asynchronous write. > - Copyright (C) 1997-2021 Free Software Foundation, Inc. > - This file is part of the GNU C Library. > - Contributed by Ulrich Drepper , 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, see > - . */ > - > -#include > - > -#include > - > - > -int > -aio_write (struct aiocb *aiocbp) > -{ > - return (__aio_enqueue_request ((aiocb_union *) aiocbp, LIO_WRITE) == NULL > - ? -1 : 0); > -} > diff --git a/sysdeps/pthread/aio_write64.c b/sysdeps/pthread/aio_write64.c > deleted file mode 100644 > index bd6dd316be..0000000000 > --- a/sysdeps/pthread/aio_write64.c > +++ /dev/null > @@ -1,30 +0,0 @@ > -/* Asynchronous write, 64bit offset version. > - Copyright (C) 1997-2021 Free Software Foundation, Inc. > - This file is part of the GNU C Library. > - Contributed by Ulrich Drepper , 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, see > - . */ > - > -#include > - > -#include > - > - > -int > -aio_write64 (struct aiocb64 *aiocbp) > -{ > - return (__aio_enqueue_request ((aiocb_union *) aiocbp, LIO_WRITE64) == NULL > - ? -1 : 0); > -} > diff --git a/sysdeps/pthread/lio_listio.c b/sysdeps/pthread/lio_listio.c > deleted file mode 100644 > index 2cab3c2254..0000000000 > --- a/sysdeps/pthread/lio_listio.c > +++ /dev/null > @@ -1,248 +0,0 @@ > -/* Enqueue and list of read or write requests. > - Copyright (C) 1997-2021 Free Software Foundation, Inc. > - This file is part of the GNU C Library. > - Contributed by Ulrich Drepper , 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, see > - . */ > - > -#ifndef lio_listio > -#include > -#include > -#include > -#include > -#include > - > -#include > - > -#define LIO_OPCODE_BASE 0 > -#endif > - > -#include > - > - > -/* We need this special structure to handle asynchronous I/O. */ > -struct async_waitlist > - { > - unsigned 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 unsigned int total = 0; > - int result = 0; > - > - if (sig == NULL) > - { > - defsigev.sigev_notify = SIGEV_NONE; > - sig = &defsigev; > - } > - > - /* Request the mutex. */ > - pthread_mutex_lock (&__aio_requests_mutex); > - > - /* 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 ((aiocb_union *) list[cnt], > - (list[cnt]->aio_lio_opcode > - | LIO_OPCODE_BASE)); > - > - 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. */ > - > - /* 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) > - __aio_notify_only (sig); > - > - 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]; > - > - 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[cnt].cond = &cond; > -#endif > - waitlist[cnt].result = &result; > - waitlist[cnt].next = requests[cnt]->waiting; > - waitlist[cnt].counterp = &total; > - waitlist[cnt].sigevp = NULL; > - requests[cnt]->waiting = &waitlist[cnt]; > - ++total; > - } > - } > - > -#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 any of the I/O requests failed, return -1 and set errno. */ > - if (result != 0) > - { > - __set_errno (result == EINTR ? EINTR : EIO); > - result = -1; > - } > - } > - else > - { > - 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 > - { > - 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; > - 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); > diff --git a/sysdeps/pthread/lio_listio64.c b/sysdeps/pthread/lio_listio64.c > deleted file mode 100644 > index 111c883a2f..0000000000 > --- a/sysdeps/pthread/lio_listio64.c > +++ /dev/null > @@ -1,33 +0,0 @@ > -/* Enqueue and list of read or write requests, 64bit offset version. > - Copyright (C) 1997-2021 Free Software Foundation, Inc. > - This file is part of the GNU C Library. > - Contributed by Ulrich Drepper , 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, see > - . */ > - > -#include > -#include > -#include > -#include > -#include > - > -#include > - > -#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 > diff --git a/sysdeps/pthread/timer_create.c b/sysdeps/pthread/timer_create.c > deleted file mode 100644 > index 2808f5b32b..0000000000 > --- a/sysdeps/pthread/timer_create.c > +++ /dev/null > @@ -1,166 +0,0 @@ > -/* Copyright (C) 2000-2021 Free Software Foundation, Inc. > - This file is part of the GNU C Library. > - Contributed by Kaz Kylheku . > - > - 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; see the file COPYING.LIB. If > - not, see . */ > - > -#include > -#include > -#include > -#include > -#include > - > -#include "posix-timer.h" > - > - > -/* Create new per-process timer using CLOCK. */ > -int > -timer_create (clockid_t clock_id, struct sigevent *evp, timer_t *timerid) > -{ > - int retval = -1; > - struct timer_node *newtimer = NULL; > - struct thread_node *thread = NULL; > - > - if (0 > -#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0 > - || clock_id == CLOCK_PROCESS_CPUTIME_ID > -#endif > -#if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0 > - || clock_id == CLOCK_THREAD_CPUTIME_ID > -#endif > - ) > - { > - /* We don't allow timers for CPU clocks. At least not in the > - moment. */ > - __set_errno (ENOTSUP); > - return -1; > - } > - > - if (clock_id != CLOCK_REALTIME) > - { > - __set_errno (EINVAL); > - return -1; > - } > - > - pthread_once (&__timer_init_once_control, __timer_init_once); > - > - if (__timer_init_failed) > - { > - __set_errno (ENOMEM); > - return -1; > - } > - > - pthread_mutex_lock (&__timer_mutex); > - > - newtimer = __timer_alloc (); > - if (__glibc_unlikely (newtimer == NULL)) > - { > - __set_errno (EAGAIN); > - goto unlock_bail; > - } > - > - if (evp != NULL) > - newtimer->event = *evp; > - else > - { > - newtimer->event.sigev_notify = SIGEV_SIGNAL; > - newtimer->event.sigev_signo = SIGALRM; > - newtimer->event.sigev_value.sival_ptr = newtimer; > - newtimer->event.sigev_notify_function = 0; > - } > - > - newtimer->event.sigev_notify_attributes = &newtimer->attr; > - newtimer->creator_pid = getpid (); > - > - switch (__builtin_expect (newtimer->event.sigev_notify, SIGEV_SIGNAL)) > - { > - case SIGEV_NONE: > - case SIGEV_SIGNAL: > - /* We have a global thread for delivering timed signals. > - If it is not running, try to start it up. */ > - thread = &__timer_signal_thread_rclk; > - if (! thread->exists) > - { > - if (__builtin_expect (__timer_thread_start (thread), > - 1) < 0) > - { > - __set_errno (EAGAIN); > - goto unlock_bail; > - } > - } > - break; > - > - case SIGEV_THREAD: > - /* Copy over thread attributes or set up default ones. */ > - if (evp->sigev_notify_attributes) > - newtimer->attr = *(pthread_attr_t *) evp->sigev_notify_attributes; > - else > - pthread_attr_init (&newtimer->attr); > - > - /* Ensure thread attributes call for deatched thread. */ > - pthread_attr_setdetachstate (&newtimer->attr, PTHREAD_CREATE_DETACHED); > - > - /* Try to find existing thread having the right attributes. */ > - thread = __timer_thread_find_matching (&newtimer->attr, clock_id); > - > - /* If no existing thread has these attributes, try to allocate one. */ > - if (thread == NULL) > - thread = __timer_thread_alloc (&newtimer->attr, clock_id); > - > - /* Out of luck; no threads are available. */ > - if (__glibc_unlikely (thread == NULL)) > - { > - __set_errno (EAGAIN); > - goto unlock_bail; > - } > - > - /* If the thread is not running already, try to start it. */ > - if (! thread->exists > - && __builtin_expect (! __timer_thread_start (thread), 0)) > - { > - __set_errno (EAGAIN); > - goto unlock_bail; > - } > - break; > - > - default: > - __set_errno (EINVAL); > - goto unlock_bail; > - } > - > - newtimer->clock = clock_id; > - newtimer->abstime = 0; > - newtimer->armed = 0; > - newtimer->thread = thread; > - > - *timerid = timer_ptr2id (newtimer); > - retval = 0; > - > - if (__builtin_expect (retval, 0) == -1) > - { > - unlock_bail: > - if (thread != NULL) > - __timer_thread_dealloc (thread); > - if (newtimer != NULL) > - { > - timer_delref (newtimer); > - __timer_dealloc (newtimer); > - } > - } > - > - pthread_mutex_unlock (&__timer_mutex); > - > - return retval; > -} > diff --git a/sysdeps/pthread/timer_delete.c b/sysdeps/pthread/timer_delete.c > deleted file mode 100644 > index c6f6d9743d..0000000000 > --- a/sysdeps/pthread/timer_delete.c > +++ /dev/null > @@ -1,68 +0,0 @@ > -/* Copyright (C) 2000-2021 Free Software Foundation, Inc. > - This file is part of the GNU C Library. > - Contributed by Kaz Kylheku . > - > - 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; see the file COPYING.LIB. If > - not, see . */ > - > -#include > -#include > -#include > -#include > - > -#include "posix-timer.h" > - > - > -/* Delete timer TIMERID. */ > -int > -timer_delete (timer_t timerid) > -{ > - struct timer_node *timer; > - int retval = -1; > - > - pthread_mutex_lock (&__timer_mutex); > - > - timer = timer_id2ptr (timerid); > - if (! timer_valid (timer)) > - /* Invalid timer ID or the timer is not in use. */ > - __set_errno (EINVAL); > - else > - { > - if (timer->armed && timer->thread != NULL) > - { > - struct thread_node *thread = timer->thread; > - assert (thread != NULL); > - > - /* If thread is cancelled while waiting for handler to terminate, > - the mutex is unlocked and timer_delete is aborted. */ > - pthread_cleanup_push (__timer_mutex_cancel_handler, &__timer_mutex); > - > - /* If timer is currently being serviced, wait for it to finish. */ > - while (thread->current_timer == timer) > - pthread_cond_wait (&thread->cond, &__timer_mutex); > - > - pthread_cleanup_pop (0); > - } > - > - /* Remove timer from whatever queue it may be on and deallocate it. */ > - timer->inuse = TIMER_DELETED; > - list_unlink_ip (&timer->links); > - timer_delref (timer); > - retval = 0; > - } > - > - pthread_mutex_unlock (&__timer_mutex); > - > - return retval; > -} > diff --git a/sysdeps/pthread/timer_getoverr.c b/sysdeps/pthread/timer_getoverr.c > deleted file mode 100644 > index c1952f80c6..0000000000 > --- a/sysdeps/pthread/timer_getoverr.c > +++ /dev/null > @@ -1,43 +0,0 @@ > -/* Copyright (C) 2000-2021 Free Software Foundation, Inc. > - This file is part of the GNU C Library. > - Contributed by Kaz Kylheku . > - > - 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; see the file COPYING.LIB. If > - not, see . */ > - > -#include > -#include > -#include > - > -#include "posix-timer.h" > - > - > -/* Get expiration overrun for timer TIMERID. */ > -int > -timer_getoverrun (timer_t timerid) > -{ > - struct timer_node *timer; > - int retval = -1; > - > - pthread_mutex_lock (&__timer_mutex); > - > - if (! timer_valid (timer = timer_id2ptr (timerid))) > - __set_errno (EINVAL); > - else > - retval = timer->overrun_count; > - > - pthread_mutex_unlock (&__timer_mutex); > - > - return retval; > -} > diff --git a/sysdeps/pthread/timer_gettime.c b/sysdeps/pthread/timer_gettime.c > deleted file mode 100644 > index dd3b4a6281..0000000000 > --- a/sysdeps/pthread/timer_gettime.c > +++ /dev/null > @@ -1,74 +0,0 @@ > -/* Copyright (C) 2000-2021 Free Software Foundation, Inc. > - This file is part of the GNU C Library. > - Contributed by Kaz Kylheku . > - > - 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; see the file COPYING.LIB. If > - not, see . */ > - > -#include > -#include > -#include > - > -#include "posix-timer.h" > - > - > -/* Get current value of timer TIMERID and store it in VLAUE. */ > -int > -timer_gettime (timer_t timerid, struct itimerspec *value) > -{ > - struct timer_node *timer; > - struct timespec now, expiry; > - int retval = -1, armed = 0, valid; > - clock_t clock = 0; > - > - pthread_mutex_lock (&__timer_mutex); > - > - timer = timer_id2ptr (timerid); > - valid = timer_valid (timer); > - > - if (valid) { > - armed = timer->armed; > - expiry = timer->expirytime; > - clock = timer->clock; > - value->it_interval = timer->value.it_interval; > - } > - > - pthread_mutex_unlock (&__timer_mutex); > - > - if (valid) > - { > - if (armed) > - { > - __clock_gettime (clock, &now); > - if (timespec_compare (&now, &expiry) < 0) > - timespec_sub (&value->it_value, &expiry, &now); > - else > - { > - value->it_value.tv_sec = 0; > - value->it_value.tv_nsec = 0; > - } > - } > - else > - { > - value->it_value.tv_sec = 0; > - value->it_value.tv_nsec = 0; > - } > - > - retval = 0; > - } > - else > - __set_errno (EINVAL); > - > - return retval; > -} > diff --git a/sysdeps/pthread/timer_settime.c b/sysdeps/pthread/timer_settime.c > deleted file mode 100644 > index c05adf166f..0000000000 > --- a/sysdeps/pthread/timer_settime.c > +++ /dev/null > @@ -1,131 +0,0 @@ > -/* Copyright (C) 2000-2021 Free Software Foundation, Inc. > - This file is part of the GNU C Library. > - Contributed by Kaz Kylheku . > - > - 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; see the file COPYING.LIB. If > - not, see . */ > - > -#include > -#include > -#include > - > -#include "posix-timer.h" > - > - > -/* Set timer TIMERID to VALUE, returning old value in OVLAUE. */ > -int > -timer_settime (timer_t timerid, int flags, const struct itimerspec *value, > - struct itimerspec *ovalue) > -{ > - struct timer_node *timer; > - struct thread_node *thread = NULL; > - struct timespec now; > - int have_now = 0, need_wakeup = 0; > - int retval = -1; > - > - timer = timer_id2ptr (timerid); > - if (timer == NULL) > - { > - __set_errno (EINVAL); > - goto bail; > - } > - > - if (! valid_nanoseconds (value->it_interval.tv_nsec) > - || ! valid_nanoseconds (value->it_value.tv_nsec)) > - { > - __set_errno (EINVAL); > - goto bail; > - } > - > - /* Will need to know current time since this is a relative timer; > - might as well make the system call outside of the lock now! */ > - > - if ((flags & TIMER_ABSTIME) == 0) > - { > - __clock_gettime (timer->clock, &now); > - have_now = 1; > - } > - > - pthread_mutex_lock (&__timer_mutex); > - timer_addref (timer); > - > - /* One final check of timer validity; this one is possible only > - until we have the mutex, because it accesses the inuse flag. */ > - > - if (! timer_valid(timer)) > - { > - __set_errno (EINVAL); > - goto unlock_bail; > - } > - > - if (ovalue != NULL) > - { > - ovalue->it_interval = timer->value.it_interval; > - > - if (timer->armed) > - { > - if (! have_now) > - { > - pthread_mutex_unlock (&__timer_mutex); > - __clock_gettime (timer->clock, &now); > - have_now = 1; > - pthread_mutex_lock (&__timer_mutex); > - timer_addref (timer); > - } > - > - timespec_sub (&ovalue->it_value, &timer->expirytime, &now); > - } > - else > - { > - ovalue->it_value.tv_sec = 0; > - ovalue->it_value.tv_nsec = 0; > - } > - } > - > - timer->value = *value; > - > - list_unlink_ip (&timer->links); > - timer->armed = 0; > - > - thread = timer->thread; > - > - /* A value of { 0, 0 } causes the timer to be stopped. */ > - if (value->it_value.tv_sec != 0 > - || __builtin_expect (value->it_value.tv_nsec != 0, 1)) > - { > - if ((flags & TIMER_ABSTIME) != 0) > - /* The user specified the expiration time. */ > - timer->expirytime = value->it_value; > - else > - timespec_add (&timer->expirytime, &now, &value->it_value); > - > - /* Only need to wake up the thread if timer is inserted > - at the head of the queue. */ > - if (thread != NULL) > - need_wakeup = __timer_thread_queue_timer (thread, timer); > - timer->armed = 1; > - } > - > - retval = 0; > - > -unlock_bail: > - timer_delref (timer); > - pthread_mutex_unlock (&__timer_mutex); > - > -bail: > - if (thread != NULL && need_wakeup) > - __timer_thread_wakeup (thread); > - > - return retval; > -} Ok. > diff --git a/sysdeps/unix/sysv/linux/alpha/aio_cancel.c b/sysdeps/unix/sysv/linux/alpha/aio_cancel.c > index 0d6da82919..9f69b080ed 100644 > --- a/sysdeps/unix/sysv/linux/alpha/aio_cancel.c > +++ b/sysdeps/unix/sysv/linux/alpha/aio_cancel.c > @@ -10,7 +10,7 @@ extern __typeof (aio_cancel) __old_aio_cancel; > > #define aio_cancel __new_aio_cancel > > -#include > +#include > > #undef aio_cancel > strong_alias (__new_aio_cancel, __new_aio_cancel64); Ok. > @@ -23,7 +23,7 @@ versioned_symbol (librt, __new_aio_cancel64, aio_cancel64, GLIBC_2_3); > #define aio_cancel __old_aio_cancel > #define ECANCELED 125 > > -#include > +#include > > #undef aio_cancel > strong_alias (__old_aio_cancel, __old_aio_cancel64); Ok. > diff --git a/sysdeps/unix/sysv/linux/sparc/aio_cancel.c b/sysdeps/unix/sysv/linux/sparc/aio_cancel.c > index 0d6da82919..9f69b080ed 100644 > --- a/sysdeps/unix/sysv/linux/sparc/aio_cancel.c > +++ b/sysdeps/unix/sysv/linux/sparc/aio_cancel.c > @@ -10,7 +10,7 @@ extern __typeof (aio_cancel) __old_aio_cancel; > > #define aio_cancel __new_aio_cancel > > -#include > +#include > > #undef aio_cancel > strong_alias (__new_aio_cancel, __new_aio_cancel64); Ok. > @@ -23,7 +23,7 @@ versioned_symbol (librt, __new_aio_cancel64, aio_cancel64, GLIBC_2_3); > #define aio_cancel __old_aio_cancel > #define ECANCELED 125 > > -#include > +#include > > #undef aio_cancel > strong_alias (__old_aio_cancel, __old_aio_cancel64); Ok. > diff --git a/sysdeps/unix/sysv/linux/wordsize-64/aio_read.c b/sysdeps/unix/sysv/linux/wordsize-64/aio_read.c > index d10fc4320b..8310b484d0 100644 > --- a/sysdeps/unix/sysv/linux/wordsize-64/aio_read.c > +++ b/sysdeps/unix/sysv/linux/wordsize-64/aio_read.c > @@ -1,6 +1,6 @@ > #define aio_read64 __renamed_aio_read64 > > -#include "../../../../pthread/aio_read.c" > +#include > > #undef aio_read64 > Ok. > diff --git a/sysdeps/unix/sysv/linux/wordsize-64/aio_write.c b/sysdeps/unix/sysv/linux/wordsize-64/aio_write.c > index b0fb469cb2..60d242f88f 100644 > --- a/sysdeps/unix/sysv/linux/wordsize-64/aio_write.c > +++ b/sysdeps/unix/sysv/linux/wordsize-64/aio_write.c > @@ -1,6 +1,6 @@ > #define aio_write64 __renamed_aio_write64 > > -#include "../../../../pthread/aio_write.c" > +#include > > #undef aio_write64 > Ok. > diff --git a/sysdeps/unix/sysv/linux/wordsize-64/lio_listio.c b/sysdeps/unix/sysv/linux/wordsize-64/lio_listio.c > index 25ee5a3507..be9fe7a9c7 100644 > --- a/sysdeps/unix/sysv/linux/wordsize-64/lio_listio.c > +++ b/sysdeps/unix/sysv/linux/wordsize-64/lio_listio.c > @@ -1,6 +1,6 @@ > #define lio_listio64 __renamed_lio_listio64 > > -#include "../../../../pthread/lio_listio.c" > +#include > > #undef lio_listio64 > > Ok.