/*******************************************************************************
* Copyright 2003-2020 Intel Corporation.
*
* This software and the related documents are Intel copyrighted  materials,  and
* your use of  them is  governed by the  express license  under which  they were
* provided to you (License).  Unless the License provides otherwise, you may not
* use, modify, copy, publish, distribute,  disclose or transmit this software or
* the related documents without Intel's prior written permission.
*
* This software and the related documents  are provided as  is,  with no express
* or implied  warranties,  other  than those  that are  expressly stated  in the
* License.
*******************************************************************************/

#if !defined(__MIC__)

#ifndef __VM_THREAD_H__
#define __VM_THREAD_H__

#include "vm_base.h"

#ifdef __cplusplus
extern "C" {
#endif

#if !defined _WIN32
#ifndef __USE_UNIX98
#define __USE_UNIX98
#endif
#include <pthread.h>
#endif

#define VM_WAIT_INFINITE 0xffffffffffffffffULL

/*
// Mutexes operations
*/
typedef struct _vm_mutex
{
#if defined _WIN32
    CRITICAL_SECTION csection;
#else
    pthread_mutex_t  mutex;
#endif
    int              valid;

} vm_mutex;

/* Invalidate a mutex */
void      vm_mutex_construct(vm_mutex *m);

/* Init a mutex, return VM_OK if success */
vm_status vm_mutex_init(vm_mutex *m);

/* Destroy a mutex */
vm_status vm_mutex_destroy(vm_mutex *m);

/* Lock the mutex with blocking. */
vm_status vm_mutex_lock(vm_mutex *m);

/* Lock the mutex without blocking, return VM_OK if success */
vm_status vm_mutex_trylock(vm_mutex *m);

/* Unlock the mutex. */
vm_status vm_mutex_unlock(vm_mutex *m);

/*
// Events operations
*/
typedef struct _vm_event
{
#if defined _WIN32
    HANDLE handle;
#else
    pthread_cond_t  cond;
    pthread_mutex_t mutex;
    int             manual;
    int             state;
#endif
} vm_event;

/* Init an event structure */
void      vm_event_construct(vm_event *e);

/* Init an event. Event is created unset. return VM_OK if success */
vm_status vm_event_init(vm_event *e, int manual_reset, int state);

/* Destroy the event */
vm_status vm_event_destroy(vm_event *e);

/* Set the event to either HIGH (>0) or LOW (0) state */
vm_status vm_event_set(vm_event *e, int state);

/* Pulse the event 0 -> 1 -> 0 */
vm_status vm_event_pulse(vm_event *e);

/* Wait for event to be high with (VM_WAIT_INFINITE) or without blocking, returns VM_OK if signaled or VM_TIMEOUT if wait is expired */
vm_status vm_event_wait(vm_event *e, unsigned long long msec);

/*
// Threads operations
*/
#if defined _WIN32
#define VM_THREAD_CALLCONVENTION __stdcall
#define vm_thread_handle HANDLE
#else
#define VM_THREAD_CALLCONVENTION
#define vm_thread_handle pthread_t
#endif

typedef enum
{
#if defined _WIN32
    VM_THREAD_PRIORITY_LOWEST   = THREAD_PRIORITY_LOWEST,
    VM_THREAD_PRIORITY_LOW      = THREAD_PRIORITY_BELOW_NORMAL,
    VM_THREAD_PRIORITY_NORMAL   = THREAD_PRIORITY_NORMAL,
    VM_THREAD_PRIORITY_HIGH     = THREAD_PRIORITY_ABOVE_NORMAL,
    VM_THREAD_PRIORITY_HIGHEST  = THREAD_PRIORITY_HIGHEST
#else
    VM_THREAD_PRIORITY_HIGHEST,
    VM_THREAD_PRIORITY_HIGH,
    VM_THREAD_PRIORITY_NORMAL,
    VM_THREAD_PRIORITY_LOW,
    VM_THREAD_PRIORITY_LOWEST
#endif
} vm_thread_priority;

typedef unsigned int (VM_THREAD_CALLCONVENTION * vm_thread_callback)(void *);

typedef struct _vm_thread
{
    vm_thread_callback p_thread_func;
    void              *p_arg;

#if defined _WIN32
    HANDLE       handle;
#else
    vm_mutex     mutex_wait;
    pthread_t    handle;
    int          valid;
    int          closure;
    volatile int alive;
#endif

} vm_thread;

/* IMPORTANT:
 *    The thread return value is always saved for the calling thread to
 *    collect. To avoid memory leak, always vm_thread_wait() for the
 *    child thread to terminate in the calling thread.
 */

/* Set the thread handler to an invalid value */
void      vm_thread_construct(vm_thread *t);

/* Create a thread. The thread is set to run at the call. Return 1 if successful */
vm_status vm_thread_create(vm_thread *t, vm_thread_callback func, void *arg);

/* Close thread after all */
vm_status vm_thread_destroy(vm_thread *t);

/* Wait for a thread with blocking (check == 0), or check thread existance,
   returns VM_OK if thread was terminated or VM_TIMEOUT if it is still running */
vm_status vm_thread_wait(vm_thread *t, int check);

/* Set thread priority. Return 1 if successful */
vm_status  vm_thread_set_priority(vm_thread *t, vm_thread_priority priority);

/*
// System info
*/
unsigned int vm_sys_info_get_avail_cpu_num(void);

#ifdef __cplusplus
}
#endif

#endif

#endif  // !defined(USE_MIC)
