aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/pthread
diff options
context:
space:
mode:
authorAlbert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>2017-09-08 00:42:10 +0200
committerAlbert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>2018-10-24 12:53:27 +0200
commitedd2c042edae009e62ddf33b76f65a9a4d2ceede (patch)
treef8bf313f2349fef5c5ec4e821c8383e1e643fb23 /sysdeps/pthread
parentab06a727ab8176482c472a2956f7458a308b29a8 (diff)
downloadglibc-edd2c042edae009e62ddf33b76f65a9a4d2ceede.tar
glibc-edd2c042edae009e62ddf33b76f65a9a4d2ceede.tar.gz
glibc-edd2c042edae009e62ddf33b76f65a9a4d2ceede.tar.bz2
glibc-edd2c042edae009e62ddf33b76f65a9a4d2ceede.zip
Y2038: add functions using futexes
This creates 64-bit time versions of the following APIs: - pthread_rwlock_timedrdlock - pthread_rwlock_timedwrlock - pthread_mutex_timedlock - pthread_cond_timedwait - sem_timedwait - aio_suspend It also creates 64-bit time versions of the following functions or macros: - lll_timedlock_elision - lll_timedlock - __lll_timedlock_wait - futex_reltimed_wait_cancelable - lll_futex_timed_wait - __pthread_cond_wait_common - futex_abstimed_wait_cancelable - lll_futex_timed_wait_bitset - do_aio_misc_wait - AIO_MISC_WAIT - __new_sem_wait_slow - do_futex_wait - __pthread_rwlock_wrlock_full - __pthread_rwlock_rdlock_full - futex_abstimed_wait
Diffstat (limited to 'sysdeps/pthread')
-rw-r--r--sysdeps/pthread/aio_suspend.c164
1 files changed, 164 insertions, 0 deletions
diff --git a/sysdeps/pthread/aio_suspend.c b/sysdeps/pthread/aio_suspend.c
index 010cbf84df..a14263df0d 100644
--- a/sysdeps/pthread/aio_suspend.c
+++ b/sysdeps/pthread/aio_suspend.c
@@ -251,3 +251,167 @@ aio_suspend (const struct aiocb *const list[], int nent,
}
weak_alias (aio_suspend, aio_suspend64)
+
+#ifdef DONT_NEED_AIO_MISC_COND
+static int
+__attribute__ ((noinline))
+do_aio_misc_wait64 (unsigned int *cntr,
+ const struct __timespec64 *timeout)
+{
+ int result = 0;
+
+ AIO_MISC_WAIT_T64 (result, *cntr, timeout, 1);
+
+ return result;
+}
+#endif
+
+int
+__aio_suspend64 (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;
+#ifdef BROKEN_THREAD_SIGNALS
+ waitlist[cnt].caller_pid = 0; /* Not needed. */
+#endif
+ requestlist[cnt]->waiting = &waitlist[cnt];
+ any = true;
+ }
+ else
+ /* We will never suspend. */
+ break;
+ }
+ else
+ /* We will never suspend. */
+ break;
+ }
+
+
+ /* Only if none of the entries is NULL or finished to be wait. */
+ if (cnt == nent && 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_wait64 (&cntr, timeout);
+#else
+ if (timeout == NULL)
+ result = pthread_cond_wait (&cond, &__aio_requests_mutex);
+ else
+ {
+ /* We have to convert the relative timeout value into an
+ absolute time value with pthread_cond_timedwait expects. */
+ struct timeval now;
+ struct timespec abstime;
+
+ __gettimeofday (&now, NULL);
+ abstime.tv_nsec = timeout->tv_nsec + now.tv_usec * 1000;
+ abstime.tv_sec = timeout->tv_sec + now.tv_sec;
+ if (abstime.tv_nsec >= 1000000000)
+ {
+ abstime.tv_nsec -= 1000000000;
+ abstime.tv_sec += 1;
+ }
+
+ result = __pthread_cond_timedwait64 (&cond,
+ &__aio_requests_mutex,
+ &abstime);
+ }
+#endif
+
+ pthread_cleanup_pop (0);
+ }
+
+ /* Now remove the entry in the waiting list for all requests
+ which didn't terminate. */
+ while (cnt-- > 0)
+ if (list[cnt] != NULL && list[cnt]->__error_code == EINPROGRESS)
+ {
+ struct waitlist **listp;
+
+ assert (requestlist[cnt] != NULL);
+
+ /* There is the chance that we cannot find our entry anymore. This
+ could happen if the request terminated and restarted again. */
+ listp = &requestlist[cnt]->waiting;
+ while (*listp != NULL && *listp != &waitlist[cnt])
+ listp = &(*listp)->next;
+
+ if (*listp != NULL)
+ *listp = (*listp)->next;
+ }
+
+#ifndef DONT_NEED_AIO_MISC_COND
+ /* Release the conditional variable. */
+ if (__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;
+}