blob: ea53a7d046a5fbe840ffeed9ccbf508579149993 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <inttypes.h>
#include <trace.h>
#include <object/futex_context.h>
#include <object/process_dispatcher.h>
#include <zircon/types.h>
#include "priv.h"
#define LOCAL_TRACE 0
// Get a reference to the thread that the user is asserting is the new owner of the futex.
// The thread must belong to the same process as the caller as futexes may not be owned
// by threads from another process.
static zx_status_t ValidateNewFutexOwner(zx_handle_t new_owner_handle,
fbl::RefPtr<ThreadDispatcher>* new_owner_thread_out) {
DEBUG_ASSERT(new_owner_thread_out != nullptr);
DEBUG_ASSERT(*new_owner_thread_out == nullptr);
if (new_owner_handle == ZX_HANDLE_INVALID) {
return ZX_OK;
}
auto up = ProcessDispatcher::GetCurrent();
zx_status_t status = up->GetDispatcherWithRights(new_owner_handle, 0, new_owner_thread_out);
if (status != ZX_OK) {
return status;
}
if ((*new_owner_thread_out)->process() != up) {
new_owner_thread_out->reset();
return ZX_ERR_INVALID_ARGS;
}
return ZX_OK;
}
// zx_status_t zx_futex_wait
zx_status_t sys_futex_wait(user_in_ptr<const zx_futex_t> value_ptr, zx_futex_t current_value,
zx_handle_t current_futex_owner, zx_time_t deadline) {
LTRACEF("futex %p current %d\n", value_ptr.get(), current_value);
ProcessDispatcher* dispatcher = ThreadDispatcher::GetCurrent()->process();
const TimerSlack slack = dispatcher->GetTimerSlackPolicy();
const Deadline slackDeadline(deadline, slack);
fbl::RefPtr<ThreadDispatcher> futex_owner_thread;
auto result = ValidateNewFutexOwner(current_futex_owner, &futex_owner_thread);
if (result != ZX_OK) {
return result;
}
return dispatcher->futex_context().FutexWait(
value_ptr, current_value, ktl::move(futex_owner_thread), slackDeadline);
}
// zx_status_t zx_futex_wake
zx_status_t sys_futex_wake(user_in_ptr<const zx_futex_t> value_ptr, uint32_t count) {
LTRACEF("futex %p count %" PRIu32 "\n", value_ptr.get(), count);
return ProcessDispatcher::GetCurrent()->futex_context().FutexWake(
value_ptr, count, FutexContext::OwnerAction::RELEASE);
}
// zx_status_t zx_futex_requeue
zx_status_t sys_futex_requeue(user_in_ptr<const zx_futex_t> wake_ptr,
uint32_t wake_count,
zx_futex_t current_value,
user_in_ptr<const zx_futex_t> requeue_ptr,
uint32_t requeue_count,
zx_handle_t requeue_owner) {
LTRACEF("futex %p wake_count %" PRIu32 "current_value %d "
"requeue_futex %p requeue_count %" PRIu32 "\n",
wake_ptr.get(), wake_count, current_value, requeue_ptr.get(), requeue_count);
fbl::RefPtr<ThreadDispatcher> requeue_owner_thread;
auto result = ValidateNewFutexOwner(requeue_owner, &requeue_owner_thread);
if (result != ZX_OK) {
return result;
}
return ProcessDispatcher::GetCurrent()->futex_context().FutexRequeue(
wake_ptr, wake_count, current_value, FutexContext::OwnerAction::RELEASE,
requeue_ptr, requeue_count, ktl::move(requeue_owner_thread));
}
// zx_status_t zx_futex_wake_single_owner
zx_status_t sys_futex_wake_single_owner(user_in_ptr<const zx_futex_t> value_ptr) {
LTRACEF("futex %p\n", value_ptr.get());
return ProcessDispatcher::GetCurrent()->futex_context().FutexWake(
value_ptr, 1u, FutexContext::OwnerAction::ASSIGN_WOKEN);
}
// zx_status_t zx_futex_requeue_single_owner
zx_status_t sys_futex_requeue_single_owner(user_in_ptr<const zx_futex_t> wake_ptr,
zx_futex_t current_value,
user_in_ptr<const zx_futex_t> requeue_ptr,
uint32_t requeue_count,
zx_handle_t requeue_owner) {
LTRACEF("futex %p current_value %d requeue_futex %p requeue_count %" PRIu32 "\n",
wake_ptr.get(), current_value, requeue_ptr.get(), requeue_count);
fbl::RefPtr<ThreadDispatcher> requeue_owner_thread;
auto result = ValidateNewFutexOwner(requeue_owner, &requeue_owner_thread);
if (result != ZX_OK) {
return result;
}
return ProcessDispatcher::GetCurrent()->futex_context().FutexRequeue(
wake_ptr, 1u, current_value, FutexContext::OwnerAction::ASSIGN_WOKEN,
requeue_ptr, requeue_count, ktl::move(requeue_owner_thread));
}
zx_status_t sys_futex_get_owner(user_in_ptr<const zx_futex_t> value_ptr,
user_out_ptr<zx_koid_t> koid) {
LTRACEF("futex %p\n", value_ptr.get());
return ProcessDispatcher::GetCurrent()->futex_context().FutexGetOwner(value_ptr, koid);
}