glibc/nptl/pthread_mutex_timedlock.c
Joseph Myers 9dd346ff43 Convert 113 more function definitions to prototype style (files with assertions).
This mostly automatically-generated patch converts 113 function
definitions in glibc from old-style K&R to prototype-style.  Following
my other recent such patches, this one deals with the case of function
definitions in files that either contain assertions or where grep
suggested they might contain assertions - and thus where it isn't
possible to use a simple object code comparison as a sanity check on
the correctness of the patch, because line numbers are changed.

A few such automatically-generated changes needed to be supplemented
by manual changes for the result to compile.  openat64 had a prototype
declaration with "..." but an old-style definition in
sysdeps/unix/sysv/linux/dl-openat64.c, and "..." needed adding to the
generated prototype in the definition (I've filed
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68024> for diagnosing
such cases in GCC; the old state was undefined behavior not requiring
a diagnostic, but one seems a good idea).  In addition, as Florian has
noted regparm attribute mismatches between declaration and definition
are only diagnosed for prototype definitions, and five functions
needed internal_function added to their definitions (in the case of
__pthread_mutex_cond_lock, via the macro definition of
__pthread_mutex_lock) to compile on i386.

After this patch is in, remaining old-style definitions are probably
most readily fixed manually before we can turn on
-Wold-style-definition for all builds.

Tested for x86_64 and x86 (testsuite).

	* crypt/md5-crypt.c (__md5_crypt_r): Convert to prototype-style
	function definition.
	* crypt/sha256-crypt.c (__sha256_crypt_r): Likewise.
	* crypt/sha512-crypt.c (__sha512_crypt_r): Likewise.
	* debug/backtracesyms.c (__backtrace_symbols): Likewise.
	* elf/dl-minimal.c (_itoa): Likewise.
	* hurd/hurdmalloc.c (malloc): Likewise.
	(free): Likewise.
	(realloc): Likewise.
	* inet/inet6_option.c (inet6_option_space): Likewise.
	(inet6_option_init): Likewise.
	(inet6_option_append): Likewise.
	(inet6_option_alloc): Likewise.
	(inet6_option_next): Likewise.
	(inet6_option_find): Likewise.
	* io/ftw.c (FTW_NAME): Likewise.
	(NFTW_NAME): Likewise.
	(NFTW_NEW_NAME): Likewise.
	(NFTW_OLD_NAME): Likewise.
	* libio/iofwide.c (_IO_fwide): Likewise.
	* libio/strops.c (_IO_str_init_static_internal): Likewise.
	(_IO_str_init_static): Likewise.
	(_IO_str_init_readonly): Likewise.
	(_IO_str_overflow): Likewise.
	(_IO_str_underflow): Likewise.
	(_IO_str_count): Likewise.
	(_IO_str_seekoff): Likewise.
	(_IO_str_pbackfail): Likewise.
	(_IO_str_finish): Likewise.
	* libio/wstrops.c (_IO_wstr_init_static): Likewise.
	(_IO_wstr_overflow): Likewise.
	(_IO_wstr_underflow): Likewise.
	(_IO_wstr_count): Likewise.
	(_IO_wstr_seekoff): Likewise.
	(_IO_wstr_pbackfail): Likewise.
	(_IO_wstr_finish): Likewise.
	* locale/programs/localedef.c (normalize_codeset): Likewise.
	* locale/programs/locarchive.c (add_locale_to_archive): Likewise.
	(add_locales_to_archive): Likewise.
	(delete_locales_from_archive): Likewise.
	* malloc/malloc.c (__libc_mallinfo): Likewise.
	* math/gen-auto-libm-tests.c (init_fp_formats): Likewise.
	* misc/tsearch.c (__tfind): Likewise.
	* nptl/pthread_attr_destroy.c (__pthread_attr_destroy): Likewise.
	* nptl/pthread_attr_getdetachstate.c
	(__pthread_attr_getdetachstate): Likewise.
	* nptl/pthread_attr_getguardsize.c (pthread_attr_getguardsize):
	Likewise.
	* nptl/pthread_attr_getinheritsched.c
	(__pthread_attr_getinheritsched): Likewise.
	* nptl/pthread_attr_getschedparam.c
	(__pthread_attr_getschedparam): Likewise.
	* nptl/pthread_attr_getschedpolicy.c
	(__pthread_attr_getschedpolicy): Likewise.
	* nptl/pthread_attr_getscope.c (__pthread_attr_getscope):
	Likewise.
	* nptl/pthread_attr_getstack.c (__pthread_attr_getstack):
	Likewise.
	* nptl/pthread_attr_getstackaddr.c (__pthread_attr_getstackaddr):
	Likewise.
	* nptl/pthread_attr_getstacksize.c (__pthread_attr_getstacksize):
	Likewise.
	* nptl/pthread_attr_init.c (__pthread_attr_init_2_1): Likewise.
	(__pthread_attr_init_2_0): Likewise.
	* nptl/pthread_attr_setdetachstate.c
	(__pthread_attr_setdetachstate): Likewise.
	* nptl/pthread_attr_setguardsize.c (pthread_attr_setguardsize):
	Likewise.
	* nptl/pthread_attr_setinheritsched.c
	(__pthread_attr_setinheritsched): Likewise.
	* nptl/pthread_attr_setschedparam.c
	(__pthread_attr_setschedparam): Likewise.
	* nptl/pthread_attr_setschedpolicy.c
	(__pthread_attr_setschedpolicy): Likewise.
	* nptl/pthread_attr_setscope.c (__pthread_attr_setscope):
	Likewise.
	* nptl/pthread_attr_setstack.c (__pthread_attr_setstack):
	Likewise.
	* nptl/pthread_attr_setstackaddr.c (__pthread_attr_setstackaddr):
	Likewise.
	* nptl/pthread_attr_setstacksize.c (__pthread_attr_setstacksize):
	Likewise.
	* nptl/pthread_condattr_setclock.c (pthread_condattr_setclock):
	Likewise.
	* nptl/pthread_create.c (__find_in_stack_list): Likewise.
	* nptl/pthread_getattr_np.c (pthread_getattr_np): Likewise.
	* nptl/pthread_mutex_cond_lock.c (__pthread_mutex_lock): Define to
	use internal_function.
	* nptl/pthread_mutex_init.c (__pthread_mutex_init): Convert to
	prototype-style function definition.
	* nptl/pthread_mutex_lock.c (__pthread_mutex_lock): Likewise.
	(__pthread_mutex_cond_lock_adjust): Likewise.  Use
	internal_function.
	* nptl/pthread_mutex_timedlock.c (pthread_mutex_timedlock):
	Convert to prototype-style function definition.
	* nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock):
	Likewise.
	* nptl/pthread_mutex_unlock.c (__pthread_mutex_unlock_usercnt):
	Likewise.
	(__pthread_mutex_unlock): Likewise.
	* nptl_db/td_ta_clear_event.c (td_ta_clear_event): Likewise.
	* nptl_db/td_ta_set_event.c (td_ta_set_event): Likewise.
	* nptl_db/td_thr_clear_event.c (td_thr_clear_event): Likewise.
	* nptl_db/td_thr_event_enable.c (td_thr_event_enable): Likewise.
	* nptl_db/td_thr_set_event.c (td_thr_set_event): Likewise.
	* nss/makedb.c (process_input): Likewise.
	* posix/fnmatch.c (__strchrnul): Likewise.
	(__wcschrnul): Likewise.
	(fnmatch): Likewise.
	* posix/fnmatch_loop.c (FCT): Likewise.
	* posix/glob.c (globfree): Likewise.
	(__glob_pattern_type): Likewise.
	(__glob_pattern_p): Likewise.
	* posix/regcomp.c (re_compile_pattern): Likewise.
	(re_set_syntax): Likewise.
	(re_compile_fastmap): Likewise.
	(regcomp): Likewise.
	(regerror): Likewise.
	(regfree): Likewise.
	* posix/regexec.c (regexec): Likewise.
	(re_match): Likewise.
	(re_search): Likewise.
	(re_match_2): Likewise.
	(re_search_2): Likewise.
	(re_search_stub): Likewise.  Use internal_function
	(re_copy_regs): Likewise.
	(re_set_registers): Convert to prototype-style function
	definition.
	(prune_impossible_nodes): Likewise.  Use internal_function.
	* resolv/inet_net_pton.c (inet_net_pton): Convert to
	prototype-style function definition.
	(inet_net_pton_ipv4): Likewise.
	* stdlib/strtod_l.c (____STRTOF_INTERNAL): Likewise.
	* sysdeps/pthread/aio_cancel.c (aio_cancel): Likewise.
	* sysdeps/pthread/aio_suspend.c (aio_suspend): Likewise.
	* sysdeps/pthread/timer_delete.c (timer_delete): Likewise.
	* sysdeps/unix/sysv/linux/dl-openat64.c (openat64): Likewise.
	Make variadic.
	* time/strptime_l.c (localtime_r): Convert to prototype-style
	function definition.
	* wcsmbs/mbsnrtowcs.c (__mbsnrtowcs): Likewise.
	* wcsmbs/mbsrtowcs_l.c (__mbsrtowcs_l): Likewise.
	* wcsmbs/wcsnrtombs.c (__wcsnrtombs): Likewise.
	* wcsmbs/wcsrtombs.c (__wcsrtombs): Likewise.
2015-10-20 11:54:09 +00:00

522 lines
14 KiB
C

/* Copyright (C) 2002-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
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
<http://www.gnu.org/licenses/>. */
#include <assert.h>
#include <errno.h>
#include <time.h>
#include <sys/param.h>
#include <sys/time.h>
#include "pthreadP.h"
#include <atomic.h>
#include <lowlevellock.h>
#include <not-cancel.h>
#include <stap-probe.h>
#ifndef lll_timedlock_elision
#define lll_timedlock_elision(a,dummy,b,c) lll_timedlock(a, b, c)
#endif
#ifndef lll_trylock_elision
#define lll_trylock_elision(a,t) lll_trylock(a)
#endif
#ifndef FORCE_ELISION
#define FORCE_ELISION(m, s)
#endif
int
pthread_mutex_timedlock (pthread_mutex_t *mutex,
const struct timespec *abstime)
{
int oldval;
pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
int result = 0;
LIBC_PROBE (mutex_timedlock_entry, 2, mutex, abstime);
/* We must not check ABSTIME here. If the thread does not block
abstime must not be checked for a valid value. */
switch (__builtin_expect (PTHREAD_MUTEX_TYPE_ELISION (mutex),
PTHREAD_MUTEX_TIMED_NP))
{
/* Recursive mutex. */
case PTHREAD_MUTEX_RECURSIVE_NP|PTHREAD_MUTEX_ELISION_NP:
case PTHREAD_MUTEX_RECURSIVE_NP:
/* Check whether we already hold the mutex. */
if (mutex->__data.__owner == id)
{
/* Just bump the counter. */
if (__glibc_unlikely (mutex->__data.__count + 1 == 0))
/* Overflow of the counter. */
return EAGAIN;
++mutex->__data.__count;
goto out;
}
/* We have to get the mutex. */
result = lll_timedlock (mutex->__data.__lock, abstime,
PTHREAD_MUTEX_PSHARED (mutex));
if (result != 0)
goto out;
/* Only locked once so far. */
mutex->__data.__count = 1;
break;
/* Error checking mutex. */
case PTHREAD_MUTEX_ERRORCHECK_NP:
/* Check whether we already hold the mutex. */
if (__glibc_unlikely (mutex->__data.__owner == id))
return EDEADLK;
/* FALLTHROUGH */
case PTHREAD_MUTEX_TIMED_NP:
FORCE_ELISION (mutex, goto elision);
simple:
/* Normal mutex. */
result = lll_timedlock (mutex->__data.__lock, abstime,
PTHREAD_MUTEX_PSHARED (mutex));
break;
case PTHREAD_MUTEX_TIMED_ELISION_NP:
elision: __attribute__((unused))
/* Don't record ownership */
return lll_timedlock_elision (mutex->__data.__lock,
mutex->__data.__spins,
abstime,
PTHREAD_MUTEX_PSHARED (mutex));
case PTHREAD_MUTEX_ADAPTIVE_NP:
if (! __is_smp)
goto simple;
if (lll_trylock (mutex->__data.__lock) != 0)
{
int cnt = 0;
int max_cnt = MIN (MAX_ADAPTIVE_COUNT,
mutex->__data.__spins * 2 + 10);
do
{
if (cnt++ >= max_cnt)
{
result = lll_timedlock (mutex->__data.__lock, abstime,
PTHREAD_MUTEX_PSHARED (mutex));
break;
}
atomic_spin_nop ();
}
while (lll_trylock (mutex->__data.__lock) != 0);
mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8;
}
break;
case PTHREAD_MUTEX_ROBUST_RECURSIVE_NP:
case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP:
case PTHREAD_MUTEX_ROBUST_NORMAL_NP:
case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
&mutex->__data.__list.__next);
oldval = mutex->__data.__lock;
do
{
again:
if ((oldval & FUTEX_OWNER_DIED) != 0)
{
/* The previous owner died. Try locking the mutex. */
int newval = id | (oldval & FUTEX_WAITERS);
newval
= atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
newval, oldval);
if (newval != oldval)
{
oldval = newval;
goto again;
}
/* We got the mutex. */
mutex->__data.__count = 1;
/* But it is inconsistent unless marked otherwise. */
mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
ENQUEUE_MUTEX (mutex);
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
/* Note that we deliberately exit here. If we fall
through to the end of the function __nusers would be
incremented which is not correct because the old
owner has to be discounted. */
return EOWNERDEAD;
}
/* Check whether we already hold the mutex. */
if (__glibc_unlikely ((oldval & FUTEX_TID_MASK) == id))
{
int kind = PTHREAD_MUTEX_TYPE (mutex);
if (kind == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP)
{
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
NULL);
return EDEADLK;
}
if (kind == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP)
{
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
NULL);
/* Just bump the counter. */
if (__glibc_unlikely (mutex->__data.__count + 1 == 0))
/* Overflow of the counter. */
return EAGAIN;
++mutex->__data.__count;
LIBC_PROBE (mutex_timedlock_acquired, 1, mutex);
return 0;
}
}
result = lll_robust_timedlock (mutex->__data.__lock, abstime, id,
PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
if (__builtin_expect (mutex->__data.__owner
== PTHREAD_MUTEX_NOTRECOVERABLE, 0))
{
/* This mutex is now not recoverable. */
mutex->__data.__count = 0;
lll_unlock (mutex->__data.__lock,
PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return ENOTRECOVERABLE;
}
if (result == ETIMEDOUT || result == EINVAL)
goto out;
oldval = result;
}
while ((oldval & FUTEX_OWNER_DIED) != 0);
mutex->__data.__count = 1;
ENQUEUE_MUTEX (mutex);
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
break;
/* The PI support requires the Linux futex system call. If that's not
available, pthread_mutex_init should never have allowed the type to
be set. So it will get the default case for an invalid type. */
#ifdef __NR_futex
case PTHREAD_MUTEX_PI_RECURSIVE_NP:
case PTHREAD_MUTEX_PI_ERRORCHECK_NP:
case PTHREAD_MUTEX_PI_NORMAL_NP:
case PTHREAD_MUTEX_PI_ADAPTIVE_NP:
case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP:
case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP:
case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
{
int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
if (robust)
/* Note: robust PI futexes are signaled by setting bit 0. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
(void *) (((uintptr_t) &mutex->__data.__list.__next)
| 1));
oldval = mutex->__data.__lock;
/* Check whether we already hold the mutex. */
if (__glibc_unlikely ((oldval & FUTEX_TID_MASK) == id))
{
if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
{
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return EDEADLK;
}
if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
{
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
/* Just bump the counter. */
if (__glibc_unlikely (mutex->__data.__count + 1 == 0))
/* Overflow of the counter. */
return EAGAIN;
++mutex->__data.__count;
LIBC_PROBE (mutex_timedlock_acquired, 1, mutex);
return 0;
}
}
oldval = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
id, 0);
if (oldval != 0)
{
/* The mutex is locked. The kernel will now take care of
everything. The timeout value must be a relative value.
Convert it. */
int private = (robust
? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
: PTHREAD_MUTEX_PSHARED (mutex));
INTERNAL_SYSCALL_DECL (__err);
int e = INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
__lll_private_flag (FUTEX_LOCK_PI,
private), 1,
abstime);
if (INTERNAL_SYSCALL_ERROR_P (e, __err))
{
if (INTERNAL_SYSCALL_ERRNO (e, __err) == ETIMEDOUT)
return ETIMEDOUT;
if (INTERNAL_SYSCALL_ERRNO (e, __err) == ESRCH
|| INTERNAL_SYSCALL_ERRNO (e, __err) == EDEADLK)
{
assert (INTERNAL_SYSCALL_ERRNO (e, __err) != EDEADLK
|| (kind != PTHREAD_MUTEX_ERRORCHECK_NP
&& kind != PTHREAD_MUTEX_RECURSIVE_NP));
/* ESRCH can happen only for non-robust PI mutexes where
the owner of the lock died. */
assert (INTERNAL_SYSCALL_ERRNO (e, __err) != ESRCH
|| !robust);
/* Delay the thread until the timeout is reached.
Then return ETIMEDOUT. */
struct timespec reltime;
struct timespec now;
INTERNAL_SYSCALL (clock_gettime, __err, 2, CLOCK_REALTIME,
&now);
reltime.tv_sec = abstime->tv_sec - now.tv_sec;
reltime.tv_nsec = abstime->tv_nsec - now.tv_nsec;
if (reltime.tv_nsec < 0)
{
reltime.tv_nsec += 1000000000;
--reltime.tv_sec;
}
if (reltime.tv_sec >= 0)
while (nanosleep_not_cancel (&reltime, &reltime) != 0)
continue;
return ETIMEDOUT;
}
return INTERNAL_SYSCALL_ERRNO (e, __err);
}
oldval = mutex->__data.__lock;
assert (robust || (oldval & FUTEX_OWNER_DIED) == 0);
}
if (__glibc_unlikely (oldval & FUTEX_OWNER_DIED))
{
atomic_and (&mutex->__data.__lock, ~FUTEX_OWNER_DIED);
/* We got the mutex. */
mutex->__data.__count = 1;
/* But it is inconsistent unless marked otherwise. */
mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
ENQUEUE_MUTEX_PI (mutex);
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
/* Note that we deliberately exit here. If we fall
through to the end of the function __nusers would be
incremented which is not correct because the old owner
has to be discounted. */
return EOWNERDEAD;
}
if (robust
&& __builtin_expect (mutex->__data.__owner
== PTHREAD_MUTEX_NOTRECOVERABLE, 0))
{
/* This mutex is now not recoverable. */
mutex->__data.__count = 0;
INTERNAL_SYSCALL_DECL (__err);
INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
__lll_private_flag (FUTEX_UNLOCK_PI,
PTHREAD_ROBUST_MUTEX_PSHARED (mutex)),
0, 0);
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return ENOTRECOVERABLE;
}
mutex->__data.__count = 1;
if (robust)
{
ENQUEUE_MUTEX_PI (mutex);
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
}
}
break;
#endif /* __NR_futex. */
case PTHREAD_MUTEX_PP_RECURSIVE_NP:
case PTHREAD_MUTEX_PP_ERRORCHECK_NP:
case PTHREAD_MUTEX_PP_NORMAL_NP:
case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
{
int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
oldval = mutex->__data.__lock;
/* Check whether we already hold the mutex. */
if (mutex->__data.__owner == id)
{
if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
return EDEADLK;
if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
{
/* Just bump the counter. */
if (__glibc_unlikely (mutex->__data.__count + 1 == 0))
/* Overflow of the counter. */
return EAGAIN;
++mutex->__data.__count;
LIBC_PROBE (mutex_timedlock_acquired, 1, mutex);
return 0;
}
}
int oldprio = -1, ceilval;
do
{
int ceiling = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK)
>> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
if (__pthread_current_priority () > ceiling)
{
result = EINVAL;
failpp:
if (oldprio != -1)
__pthread_tpp_change_priority (oldprio, -1);
return result;
}
result = __pthread_tpp_change_priority (oldprio, ceiling);
if (result)
return result;
ceilval = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
oldprio = ceiling;
oldval
= atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
ceilval | 1, ceilval);
if (oldval == ceilval)
break;
do
{
oldval
= atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
ceilval | 2,
ceilval | 1);
if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval)
break;
if (oldval != ceilval)
{
/* Reject invalid timeouts. */
if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
{
result = EINVAL;
goto failpp;
}
struct timeval tv;
struct timespec rt;
/* Get the current time. */
(void) __gettimeofday (&tv, NULL);
/* Compute relative timeout. */
rt.tv_sec = abstime->tv_sec - tv.tv_sec;
rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
if (rt.tv_nsec < 0)
{
rt.tv_nsec += 1000000000;
--rt.tv_sec;
}
/* Already timed out? */
if (rt.tv_sec < 0)
{
result = ETIMEDOUT;
goto failpp;
}
lll_futex_timed_wait (&mutex->__data.__lock,
ceilval | 2, &rt,
PTHREAD_MUTEX_PSHARED (mutex));
}
}
while (atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
ceilval | 2, ceilval)
!= ceilval);
}
while ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval);
assert (mutex->__data.__owner == 0);
mutex->__data.__count = 1;
}
break;
default:
/* Correct code cannot set any other type. */
return EINVAL;
}
if (result == 0)
{
/* Record the ownership. */
mutex->__data.__owner = id;
++mutex->__data.__nusers;
LIBC_PROBE (mutex_timedlock_acquired, 1, mutex);
}
out:
return result;
}