/*
 * remote_condvar.h: POSIX condition variable definition.     
 * 
 * Authors  Alain Greiner (2016,2017,2018,2019)
 *
 * Copyright (c) UPMC Sorbonne Universites
 *
 * This file is part of ALMOS-MKH.
 *
 * ALMOS-MKH is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2.0 of the License.
 *
 * ALMOS-MKH is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ALMOS-kernel; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#ifndef _CONDVAR_H_
#define _CONDVAR_H_

#include <kernel_config.h>
#include <hal_kernel_types.h>
#include <remote_busylock.h>
#include <xlist.h>

/*******************************************************************************************
 * This file defines the ALMOS-MKH implentation of an user level, POSIX compliant condvar.
 *
 * It can be used by muti-threaded user applications to synchronise user threads
 * running in different clusters.
 *
 * A condvar is declared by a given user process as a "pthread_cond_t" global variable.
 * This user type is implemented as an unsigned long, but the value is not used by the 
 * kernel. ALMOS-MKH uses only the mutex virtual address as an identifier.
 * For each user condvar, ALMOS-MKH creates a kernel "remote_condvar_t" structure,
 * dynamically allocated in the reference cluster by the remote_condvar_create() function, 
 * and destroyed by the remote_condvar_destroy() function, using RPC if the calling thread
 * is not running in the reference cluster.
 * 
 * The blocking "remote_condvar_wait() function allows the calling thread to efficiently
 * wait for a change in a shared user object. The calling thread blocks and register in
 * a waiting queue attached to the condvar. The blocked thread is unblocked by another
 * thread calling the remote_convar signal() or remote_condvar_broadcast().
 * The three associated methods wait(), signal() and broadcast() must be called
 * by a thread holding the mutex associated to the condvar.
 ******************************************************************************************/

/*******************************************************************************************
 * This structure defines the kernel implementation of a condvar.
 ******************************************************************************************/

typedef struct remote_condvar_s
{
    remote_busylock_t lock;         /*! lock protecting the condvar state                 */
    intptr_t          ident;        /*! virtual address in user space == identifier       */
    xlist_entry_t     root;         /*! root of waiting threads queue                     */
    xlist_entry_t     list;         /*! member of list of condvars in same process        */
}
remote_condvar_t;

/*********************************************************************************************
 * This function returns an extended pointer on the remote condvar identified
 * by its virtual address in a given user process. It makes an associative search, 
 * scanning the list of user condvars rooted in the reference process descriptor.
 *********************************************************************************************
 * @ ident    : semaphore virtual address, used as identifier.
 * @ returns extended pointer on semaphore if success / returns XPTR_NULL if not found. 
 ********************************************************************************************/
xptr_t remote_condvar_from_ident( intptr_t  ident );

/*******************************************************************************************
 * This function implements the CONVAR_INIT operation.
 * This function creates and initializes a remote_condvar, identified by its virtual
 * address <vaddr> in the client process reference cluster, using remote access.
 * It registers this user condvar in the reference process descriptor.
 *******************************************************************************************
 * @ vaddr         : [in]  condvar virtual addresss, used as identifier.
 ******************************************************************************************/
error_t remote_condvar_create( intptr_t   vaddr );

/*******************************************************************************************
 * This function implements the CONVAR_DESTROY operation.
 * This function creates and initializes a remote_condvar, identified by its virtual
 * address in the client process reference cluster, and registers it in process descriptor.
 *******************************************************************************************
 * @ condvar_xp : [in] extended pointer on buffer to store xptr on created condvar.
 ******************************************************************************************/
void remote_condvar_destroy( xptr_t condvar_xp );

/*******************************************************************************************
 * This function implements the CONDVAR_WAIT operation.
 * It atomically releases the mutex identified by the <mutex_xp> argument, 
 * registers the calling thread in the condvar waiting queue identified by the
 * <condvar_xp> argument, blocks and deschedules this calling thread.
 * Later, when the calling thread resume, this function re-acquire the mutex and returns.
 * WARNING: the calling thread must hold the mutex associated to the condvar.
 *******************************************************************************************
 * @ condvar_xp : [in] extended pointer on condvar.
 * @ mutex_xp   : [in] extended pointer on mutex.
 ******************************************************************************************/
void remote_condvar_wait( xptr_t condvar_xp,
                          xptr_t mutex_xp );

/*******************************************************************************************
 * This function implements the CONDVAR_SIGNAL operation.
 * It remove one waiting thread from a remote_condvar waiting queue identified by the
 * <condvar_xp> argument and unblocks this thread.
 * It does nothing if the queue is empty.
 * WARNING: the calling thread must hold the mutex associated to the condvar.
 *******************************************************************************************
 * @ condvar_xp : extended pointer on remote_condvar.
 ******************************************************************************************/
void remote_condvar_signal( xptr_t condvar_xp );

/*******************************************************************************************
 * This function implements the CONDVAR_BROADCAST operation.
 * It removes all threads from a remote_condvar waiting queue identified by the
 * <condvar_xp> argument, and unblocks all these threads. 
 * It does nothing if the queue is empty.
 * WARNING: the calling thread must hold the mutex associated to the condvar.
 *******************************************************************************************
 * @ condvar_xp : extended pointer on remote_condvar.
 ******************************************************************************************/
void remote_condvar_broadcast( xptr_t condvar_xp );

#endif	/* _CONDVAR_H_ */
