blob: e0810e4de94dc3d5a30b9ed5aa27fa0657bce9c9 [file] [log] [blame]
/* *******************************************************************************
* Copyright (c) 2010-2013 Google, Inc. All rights reserved.
* Copyright (c) 2011 Massachusetts Institute of Technology All rights reserved.
* Copyright (c) 2000-2010 VMware, Inc. All rights reserved.
* *******************************************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
/* Copyright (c) 2001-2003 Massachusetts Institute of Technology */
/* Copyright (c) 2000-2001 Hewlett-Packard Company */
/*
* ksynch_linux.c - synchronization via the kernel
*
* i#96/PR 295561: use futex(2) if available.
*/
#include "../globals.h"
#include "ksynch.h"
#include <linux/futex.h> /* for futex op code */
#include "include/syscall.h" /* our own local copy */
#ifndef LINUX
# error Linux-only
#endif
/* Does the kernel support SYS_futex syscall? Safe to initialize assuming
* no futex support.
*/
static bool kernel_futex_support = false;
void
ksynch_init(void)
{
/* Determines whether the kernel supports SYS_futex syscall or not.
* From man futex(2): initial futex support was merged in 2.5.7, in current six
* argument format since 2.6.7.
*/
volatile int futex_for_test = 0;
ptr_int_t res = dynamorio_syscall(SYS_futex, 6, &futex_for_test, FUTEX_WAKE, 1,
NULL, NULL, 0);
kernel_futex_support = (res >= 0);
ASSERT_CURIOSITY(kernel_futex_support);
}
void
ksynch_exit(void)
{
}
bool
ksynch_kernel_support(void)
{
return kernel_futex_support;
}
/* We use volatile int rather than bool since these are used as futexes.
* 0 is unset, 1 is set, and no other value is used.
*/
bool
ksynch_init_var(volatile int *futex)
{
ASSERT(ALIGNED(futex, sizeof(int)));
*futex = 0;
return true;
}
bool
ksynch_var_initialized(volatile int *futex)
{
return (*futex != -1);
}
bool
ksynch_free_var(volatile int *futex)
{
/* nothing to be done */
return true;
}
/* Waits on the futex until woken if the kernel supports SYS_futex syscall
* and the futex's value has not been changed from mustbe. Does not block
* if the kernel doesn't support SYS_futex. Returns 0 if woken by another thread,
* and negative value for all other cases.
*/
ptr_int_t
ksynch_wait(volatile int *futex, int mustbe)
{
ptr_int_t res;
ASSERT(ALIGNED(futex, sizeof(int)));
if (kernel_futex_support) {
/* XXX: Having debug timeout like win32 os_wait_event() would be useful */
res = dynamorio_syscall(SYS_futex, 6, futex, FUTEX_WAIT, mustbe, NULL,
NULL, 0);
} else {
res = -1;
}
return res;
}
/* Wakes up at most one thread waiting on the futex if the kernel supports
* SYS_futex syscall. Does nothing if the kernel doesn't support SYS_futex.
*/
ptr_int_t
ksynch_wake(volatile int *futex)
{
ptr_int_t res;
ASSERT(ALIGNED(futex, sizeof(int)));
if (kernel_futex_support) {
res = dynamorio_syscall(SYS_futex, 6, futex, FUTEX_WAKE, 1, NULL, NULL, 0);
} else {
res = -1;
}
return res;
}
/* Wakes up all the threads waiting on the futex if the kernel supports
* SYS_futex syscall. Does nothing if the kernel doesn't support SYS_futex.
*/
ptr_int_t
ksynch_wake_all(volatile int *futex)
{
ptr_int_t res;
ASSERT(ALIGNED(futex, sizeof(int)));
if (kernel_futex_support) {
do {
res = dynamorio_syscall(SYS_futex, 6, futex, FUTEX_WAKE, INT_MAX,
NULL, NULL, 0);
} while (res == INT_MAX);
res = 0;
} else {
res = -1;
}
return res;
}
volatile int *
mutex_get_contended_event(mutex_t *lock)
{
if (!ksynch_var_initialized(&lock->contended_event)) {
/* We just don't want to clobber an in-use event */
atomic_compare_exchange_int((int*)&lock->contended_event, -1, (int)0);
}
return &lock->contended_event;
}
void
mutex_free_contended_event(mutex_t *lock)
{
/* Nothing to do */
}