Julian Seward 7c542ccd39 Add new files resulting from merging in the 2.4.0 line. Many of these
seem to be simply duplication of the x86 instruction set tests into
the addrcheck and helgrind trees.  I'm not sure what this duplication
achieves.



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3264
2005-03-10 23:23:45 +00:00

113 lines
2.3 KiB
C

#include "core.h"
#if FUTEX_SEMA
/*
Futex-based semaphore operations.
Taken from futex-2.2/usersem.c
Based on work by Matthew Kirkwood <matthew@hairy.beasts.org>.
*/
#define FUTEX_PASSED (-(1024 * 1024 * 1024))
static inline Int sys_futex(Int *futex, Int op, Int val, struct vki_timespec *rel)
{
return VG_(do_syscall)(__NR_futex, futex, op, val, rel);
}
/* Returns -1 on fail, 0 on wakeup, 1 on pass, 2 on didn't sleep */
int __futex_down_slow(vg_sema_t *futx, int val, struct vki_timespec *rel)
{
Int ret;
ret = sys_futex(&futx->count, VKI_FUTEX_WAIT, val, rel);
if (ret == 0) {
/* <= in case someone else decremented it */
if (futx->count <= FUTEX_PASSED) {
futx->count = -1;
return 1;
}
return 0;
}
/* EWOULDBLOCK just means value changed before we slept: loop */
if (ret == -VKI_EWOULDBLOCK)
return 2;
return -1;
}
int __futex_up_slow(vg_sema_t *futx)
{
futx->count = 1;
__futex_commit();
return sys_futex(&futx->count, VKI_FUTEX_WAKE, 1, NULL);
}
void VG_(sema_init)(vg_sema_t *sema)
{
sema->count = 1;
__futex_commit();
}
#else /* !FUTEX_SEMA */
/*
Slower but more portable pipe-based token passing scheme.
*/
void VG_(sema_init)(vg_sema_t *sema)
{
VG_(pipe)(sema->pipe);
sema->pipe[0] = VG_(safe_fd)(sema->pipe[0]);
sema->pipe[1] = VG_(safe_fd)(sema->pipe[1]);
sema->owner_thread = -1;
/* create initial token */
VG_(write)(sema->pipe[1], "T", 1);
}
void VG_(sema_deinit)(vg_sema_t *sema)
{
VG_(close)(sema->pipe[0]);
VG_(close)(sema->pipe[1]);
sema->pipe[0] = sema->pipe[1] = -1;
}
/* get a token */
void VG_(sema_down)(vg_sema_t *sema)
{
Char buf[2] = { 'x' };
Int ret;
Int lwpid = VG_(gettid)();
vg_assert(sema->owner_thread != lwpid); /* can't have it already */
again:
ret = VG_(read)(sema->pipe[0], buf, 2);
if (ret == -VKI_EINTR)
goto again;
vg_assert(ret == 1); /* should get exactly 1 token */
vg_assert(buf[0] == 'T');
sema->owner_thread = lwpid;
}
/* put token back */
void VG_(sema_up)(vg_sema_t *sema)
{
Int ret;
vg_assert(sema->owner_thread == VG_(gettid)()); /* must have it */
sema->owner_thread = 0;
ret = VG_(write)(sema->pipe[1], "T", 1);
vg_assert(ret == 1);
}
#endif /* FUTEX_SEMA */