#line 1 "/build/ecl/src/ecl-26.3.27/src/c/threads/condition_variable.d"
/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/* vim: set filetype=c tabstop=2 shiftwidth=2 expandtab: */

/*
 * condition_variable.d - condition variables
 *
 * Copyright (c) 2003, Juan Jose Garcia Ripoll
 * Copyright (c) 2020, Marius Gerbershagen
 *
 * See file 'LICENSE' for the copyright details.
 *
 */

#ifndef __sun__ /* See unixinit.d for this */
#define _XOPEN_SOURCE 600	/* For pthread mutex attributes */
#endif
#define ECL_INCLUDE_MATH_H
#include <ecl/ecl.h>
#ifdef ECL_WINDOWS_THREADS
# include <windows.h>
#else
# include <pthread.h>
#endif
#include <ecl/internal.h>
#include <ecl/ecl-inl.h>

/*----------------------------------------------------------------------
 * CONDITION VARIABLES
 */

cl_object
mp_make_condition_variable(void)
{
  cl_env_ptr env = ecl_process_env();
  cl_object output = ecl_alloc_object(t_condition_variable);
  ecl_disable_interrupts_env(env);
  ecl_cond_var_init(&output->condition_variable.cv);
  ecl_set_finalizer_unprotected(output, ECL_T);
  ecl_enable_interrupts_env(env);
  {
#line 40
	const cl_env_ptr the_env = ecl_process_env();
#line 40
	#line 40
	cl_object __value0 = output;
#line 40
	the_env->nvalues = 1;
#line 40
	the_env->values[0] = __value0;
#line 40
	#line 40
	return __value0;
#line 40
}

}

cl_object
mp_condition_variable_wait(cl_object cv, cl_object lock)
{
  cl_env_ptr env = ecl_process_env();
  int rc;
  cl_fixnum counter;
  cl_object owner;
  if (ecl_unlikely(ecl_t_of(cv) != t_condition_variable)) {
    FEwrong_type_nth_arg(ecl_make_fixnum(/*MP::CONDITION-VARIABLE-WAIT*/1466), 1, cv,
                         ecl_make_fixnum(/*MP::CONDITION-VARIABLE*/1441));
  }
  if (ecl_unlikely(ecl_t_of(lock) != t_lock)) {
    FEwrong_type_nth_arg(ecl_make_fixnum(/*MP::CONDITION-VARIABLE-WAIT*/1466), 2, lock,
                         ecl_make_fixnum(/*MP::LOCK*/1440));
  }
  if (ecl_unlikely(lock->lock.recursive)) {
    FEerror("mp:condition-variable-wait can not be used with recursive"
            " locks:~%~S", 1, lock);
  }
  if (ecl_unlikely(lock->lock.owner != env->own_process)) {
    FEerror("Attempt to wait on a condition variable using lock~%~S"
            "~%which is not owned by process~%~S", 2, lock, env->own_process);
  }
  ecl_disable_interrupts_env(env);
  counter = lock->lock.counter;
  owner = lock->lock.owner;
  lock->lock.counter = 0;
  lock->lock.owner = ECL_NIL;
  ecl_enable_interrupts_env(env);
  rc = ecl_cond_var_wait(&cv->condition_variable.cv, &lock->lock.mutex);
  ecl_disable_interrupts_env(env);
  lock->lock.owner = owner;
  lock->lock.counter = counter;
  ecl_enable_interrupts_env(env);
  if (ecl_unlikely(rc != ECL_MUTEX_SUCCESS)) {
    if (rc == ECL_MUTEX_NOT_OWNED) {
      FEerror_not_owned(lock);
    } else {
      FEunknown_lock_error(lock);
    }
  }
  {
#line 84
	const cl_env_ptr the_env = ecl_process_env();
#line 84
	#line 84
	cl_object __value0 = ECL_T;
#line 84
	the_env->nvalues = 1;
#line 84
	the_env->values[0] = __value0;
#line 84
	#line 84
	return __value0;
#line 84
}

}

cl_object
mp_condition_variable_timedwait(cl_object cv, cl_object lock, cl_object seconds)
{
  cl_env_ptr env = ecl_process_env();
  int rc;
  cl_fixnum counter;
  cl_object owner;

  if (ecl_unlikely(ecl_t_of(cv) != t_condition_variable)) {
    FEwrong_type_nth_arg(ecl_make_fixnum(/*MP::CONDITION-VARIABLE-TIMEDWAIT*/1467),
                         1, cv, ecl_make_fixnum(/*MP::CONDITION-VARIABLE*/1441));
  }
  if (ecl_unlikely(ecl_t_of(lock) != t_lock)) {
    FEwrong_type_nth_arg(ecl_make_fixnum(/*MP::CONDITION-VARIABLE-TIMEDWAIT*/1467),
                         2, lock, ecl_make_fixnum(/*MP::LOCK*/1440));
  }
  if (ecl_unlikely(lock->lock.recursive)) {
    FEerror("mp:condition-variable-timedwait can not be used with recursive"
            " locks:~%~S", 1, lock);
  }
  if (ecl_unlikely(lock->lock.owner != env->own_process)) {
    FEerror("Attempt to wait on a condition variable using lock~%~S"
            "~%which is not owned by process~%~S", 2, lock, env->own_process);
  }
  /* INV: ecl_minusp() makes sure `seconds' is real */
  if (ecl_unlikely(ecl_minusp(seconds))) {
    cl_error(9, ECL_SYM("SIMPLE-TYPE-ERROR",776), ECL_SYM(":FORMAT-CONTROL",1272),
             make_constant_base_string("Not a non-negative number ~S"),
             ECL_SYM(":FORMAT-ARGUMENTS",1271), cl_list(1, seconds),
             ECL_SYM(":EXPECTED-TYPE",1263), ECL_SYM("REAL",706), ECL_SYM(":DATUM",1245), seconds);
  }
  ecl_disable_interrupts_env(env);
  counter = lock->lock.counter;
  owner = lock->lock.owner;
  lock->lock.counter = 0;
  lock->lock.owner = ECL_NIL;
  ecl_enable_interrupts_env(env);

  rc = ecl_cond_var_timedwait(&cv->condition_variable.cv, &lock->lock.mutex, ecl_to_double(seconds));

  ecl_disable_interrupts_env(env);
  lock->lock.owner = owner;
  lock->lock.counter = counter;
  ecl_enable_interrupts_env(env);

  if (ecl_unlikely(rc != ECL_MUTEX_SUCCESS && rc != ECL_MUTEX_TIMEOUT)) {
    if (rc == ECL_MUTEX_NOT_OWNED) {
      FEerror_not_owned(lock);
    } else {
      FEunknown_lock_error(lock);
    }
  }
  {
#line 139
	const cl_env_ptr the_env = ecl_process_env();
#line 139
	#line 139
	cl_object __value0 = (rc == ECL_MUTEX_SUCCESS ? ECL_T : ECL_NIL);
#line 139
	the_env->nvalues = 1;
#line 139
	the_env->values[0] = __value0;
#line 139
	#line 139
	return __value0;
#line 139
}

}

cl_object
mp_condition_variable_signal(cl_object cv)
{
  if (ecl_unlikely(ecl_t_of(cv) != t_condition_variable)) {
    FEwrong_type_only_arg(ecl_make_fixnum(/*MP::CONDITION-VARIABLE-SIGNAL*/1468),
                          cv, ecl_make_fixnum(/*MP::CONDITION-VARIABLE*/1441));
  }
  ecl_cond_var_signal(&cv->condition_variable.cv);
  {
#line 150
	const cl_env_ptr the_env = ecl_process_env();
#line 150
	#line 150
	cl_object __value0 = ECL_T;
#line 150
	the_env->nvalues = 1;
#line 150
	the_env->values[0] = __value0;
#line 150
	#line 150
	return __value0;
#line 150
}

}

cl_object
mp_condition_variable_broadcast(cl_object cv)
{
  if (ecl_unlikely(ecl_t_of(cv) != t_condition_variable)) {
    FEwrong_type_only_arg(ecl_make_fixnum(/*MP::CONDITION-VARIABLE-BROADCAST*/1469),
                          cv, ecl_make_fixnum(/*MP::CONDITION-VARIABLE*/1441));
  }
  ecl_cond_var_broadcast(&cv->condition_variable.cv);
  {
#line 161
	const cl_env_ptr the_env = ecl_process_env();
#line 161
	#line 161
	cl_object __value0 = ECL_T;
#line 161
	the_env->nvalues = 1;
#line 161
	the_env->values[0] = __value0;
#line 161
	#line 161
	return __value0;
#line 161
}

}

