/* XXX cleanup these includes */
+#define __STDC_LIMIT_MACROS
+
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "arch.h"
#include "mm/gc.hpp"
-#include "mm/memory.h"
+#include "mm/memory.hpp"
#if defined(ENABLE_GC_CACAO)
# include "mm/cacao-gc/gc.h"
#endif
#include "native/llni.h"
-#include "native/native.h"
+#include "native/native.hpp"
#include "threads/condition.hpp"
#include "threads/lock.hpp"
#include "threads/threadlist.hpp"
#include "threads/thread.hpp"
-#include "toolbox/logging.h"
+#include "toolbox/logging.hpp"
#include "vm/jit/builtin.hpp"
#include "vm/exceptions.hpp"
#include "vm/globals.hpp"
#include "vm/javaobjects.hpp"
#include "vm/options.h"
-#include "vm/signallocal.h"
+#include "vm/signallocal.hpp"
#include "vm/string.hpp"
#include "vm/vm.hpp"
*******************************************************************************/
-static void threads_wait_with_timeout(threadobject *t, struct timespec *wakeupTime)
+static void threads_wait_with_timeout(threadobject *t, struct timespec *wakeupTime, bool parking)
{
// Acquire the waitmutex.
t->waitmutex->lock();
if (wakeupTime->tv_sec || wakeupTime->tv_nsec) {
/* with timeout */
- while (!t->interrupted && !t->signaled
+ while (!t->interrupted && !(parking ? t->park_permit : t->signaled)
&& threads_current_time_is_earlier_than(wakeupTime))
{
- thread_set_state_timed_waiting(t);
+ if (parking)
+ thread_set_state_timed_parked(t);
+ else
+ thread_set_state_timed_waiting(t);
t->waitcond->timedwait(t->waitmutex, wakeupTime);
}
else {
/* no timeout */
- while (!t->interrupted && !t->signaled) {
- thread_set_state_waiting(t);
+ while (!t->interrupted && !(parking ? t->park_permit : t->signaled)) {
+ if (parking)
+ thread_set_state_parked(t);
+ else
+ thread_set_state_waiting(t);
t->waitcond->wait(t->waitmutex);
}
}
+ if (parking)
+ t->park_permit = false;
+
// Release the waitmutex.
t->waitmutex->unlock();
}
/* wait */
- threads_wait_with_timeout(thread, &wakeupTime);
+ threads_wait_with_timeout(thread, &wakeupTime, false);
}
static void threads_calc_absolute_time(struct timespec *tm, s8 millis, s4 nanos)
{
- if ((millis != 0x7fffffffffffffffLLU) && (millis || nanos)) {
+ // (at least with GNU classpath) we know that 0 <= nanos <= 999999
+ do {
+ if (!millis && !nanos)
+ break;
struct timeval tv;
- long nsec;
gettimeofday(&tv, NULL);
- tv.tv_sec += millis / 1000;
+ s8 secs = tv.tv_sec + millis / 1000;
+ if (secs > INT32_MAX) // integer overflow
+ break;
+ tv.tv_sec = secs;
millis %= 1000;
- nsec = tv.tv_usec * 1000 + (s4) millis * 1000000 + nanos;
+ long nsec = tv.tv_usec * 1000 + (s4) millis * 1000000 + nanos;
tm->tv_sec = tv.tv_sec + nsec / 1000000000;
+ if (tm->tv_sec < tv.tv_sec) // integer overflow
+ break;
tm->tv_nsec = nsec % 1000000000;
- }
- else {
- tm->tv_sec = 0;
- tm->tv_nsec = 0;
- }
+ return;
+ } while (0);
+ tm->tv_sec = 0;
+ tm->tv_nsec = 0;
}
else {
threads_calc_absolute_time(&wakeupTime, millis, nanos);
- threads_wait_with_timeout(t, &wakeupTime);
+ threads_wait_with_timeout(t, &wakeupTime, false);
interrupted = thread_is_interrupted(t);
}
}
+/**
+ * Park the current thread for the specified amount of time or until a
+ * specified deadline.
+ *
+ * @param absolute Is the time in nanos a deadline or a duration?
+ * @param nanos Nanoseconds to park (absolute=false)
+ * or deadline in milliseconds (absolute=true)
+ */
+void threads_park(bool absolute, int64_t nanos)
+{
+ threadobject *t;
+ struct timespec wakeupTime;
+
+ t = thread_get_current();
+
+ if (absolute) {
+ wakeupTime.tv_nsec = 0;
+ wakeupTime.tv_sec = nanos / 1000; /* milliseconds */
+ }
+ else
+ threads_calc_absolute_time(&wakeupTime, nanos / 1000000, nanos % 1000000);
+
+ threads_wait_with_timeout(t, &wakeupTime, true);
+}
+
+/**
+ * Unpark the specified thread.
+ *
+ * @param t The thread to unpark.
+ */
+void threads_unpark(threadobject *t)
+{
+ t->waitmutex->lock();
+
+ t->waitcond->signal();
+
+ t->park_permit = true;
+
+ t->waitmutex->unlock();
+}
+
/* threads_yield ***************************************************************