blob: 262304d9973248a5d0fc4d02530e55a478a14ffa [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file thread_native_park.c
* @brief Hythread park/unpark related functions
*/
#include <apr_atomic.h>
#include <open/hythread_ext.h>
#include "port_mutex.h"
#include "thread_private.h"
/**
* Parks the current thread.
*
* Stop the current thread from executing until it is unparked,
* interrupted, or the specified timeout elapses.
*
* Unlike wait or sleep, the interrupted flag is NOT cleared by this API.
*
* @param[in] millis
* @param[in] nanos
*
* @return 0 - if the thread is unparked<br>
* TM_ERROR_INTERRUPT if the thread was interrupted while parked<br>
*
* @see hythread_unpark
*/
IDATA VMCALL hythread_park(I_64 millis, IDATA nanos) {
IDATA status;
IDATA result = TM_ERROR_NONE;
hythread_t self = hythread_self();
hythread_monitor_t mon;
assert(self);
// Grab thread monitor
mon = self->monitor;
status = hythread_monitor_enter(mon);
assert(status == TM_ERROR_NONE);
assert(mon->recursion_count == 0);
mon->owner = NULL;
mon->wait_count++;
// Set thread state
status = port_mutex_lock(&self->mutex);
assert(status == TM_ERROR_NONE);
self->waited_monitor = mon;
if (!(self->state & TM_THREAD_STATE_UNPARKED)) {
// if thread is not unparked stop the current thread from executing
self->state |= TM_THREAD_STATE_PARKED;
status = port_mutex_unlock(&self->mutex);
assert(status == TM_ERROR_NONE);
result = condvar_wait_impl(&mon->condition, &mon->mutex,
millis, nanos, WAIT_INTERRUPTABLE);
// Restore thread state
status = port_mutex_lock(&self->mutex);
assert(status == TM_ERROR_NONE);
}
self->state &= ~(TM_THREAD_STATE_PARKED|TM_THREAD_STATE_UNPARKED);
self->waited_monitor = NULL;
status = port_mutex_unlock(&self->mutex);
assert(status == TM_ERROR_NONE);
// Release thread monitor
mon->wait_count--;
mon->owner = self;
assert(mon->notify_count <= mon->wait_count);
status = hythread_monitor_exit(mon);
assert(status == TM_ERROR_NONE);
if (self->request) {
hythread_safe_point();
hythread_exception_safe_point();
}
// the status should be restored for j.u.c.LockSupport
if (result == TM_ERROR_INTERRUPT) {
apr_atomic_set32(&self->interrupted, TRUE);
}
return result;
}
/**
* Unparks the specified thread.
*
* If the thread is parked, it will return from park.
* If the thread is not parked, its 'UNPARKED' flag will be set, and it will return
* immediately the next time it is parked.
*
* Note that unparks are not counted. Unparking a thread once is the same as unparking
* it n times.
*
* @see hythread_park
*/
void VMCALL hythread_unpark(hythread_t thread) {
IDATA status;
hythread_monitor_t mon;
if (thread == NULL) {
return;
}
status = port_mutex_lock(&thread->mutex);
assert(status == TM_ERROR_NONE);
if (thread->state & TM_THREAD_STATE_PARKED) {
thread->state &= ~TM_THREAD_STATE_PARKED;
mon = thread->waited_monitor;
assert(mon);
status = port_mutex_unlock(&thread->mutex);
assert(status == TM_ERROR_NONE);
// Notify parked thread
status = port_mutex_lock(&mon->mutex);
assert(status == TM_ERROR_NONE);
status = hycond_notify_all(&mon->condition);
assert(status == TM_ERROR_NONE);
status = port_mutex_unlock(&mon->mutex);
assert(status == TM_ERROR_NONE);
} else {
thread->state |= TM_THREAD_STATE_UNPARKED;
status = port_mutex_unlock(&thread->mutex);
assert(status == TM_ERROR_NONE);
}
}