/* Copyright (c) 2020-2022 The Creators of Simphone

   See the file COPYING.LESSER.txt for copying permission.
*/

#ifndef _SPTH_H_
#define _SPTH_H_

#ifdef __cplusplus
extern "C" {
#endif

#if HAVE_LIBPTH

#define PTH_SYSCALL_SOFT 0
#include <pth.h>

#define pth_unprotect()
#define pth_protect_()
#define PTH_UNPROTECT(CODE) (CODE)
#define PTH_PROTECT_(CODE) (CODE)
#define PTH_UNPROTECT_PROTECT_(CODE) (CODE)
#define pth_get_handle(tid) 0

#define pth_mutex_destroy(mutex)
#define pth_cond_destroy(cond)

#define pth_mutex_acquire_ pth_mutex_acquire
#define pth_cond_await_ pth_cond_await
#define pth_cond_notify_ pth_cond_notify

#define pth_join_ pth_join
#define pth_wait_ pth_wait
#define pth_usleep_ pth_usleep
#define pth_sleep_ pth_sleep

#define pth_connect_ pth_connect
#define pth_accept_ pth_accept
#define pth_select_ pth_select
#define pth_poll_ pth_poll

#define pth_read_ pth_read
#define pth_write_ pth_write
#define pth_recv_ pth_recv
#define pth_send_ pth_send

#define pth_recvmsg_ pth_recvmsg
#define pth_sendmsg_ pth_sendmsg
#define pth_waitpid_ pth_waitpid

#else

/* this emulates part of the pth API using nPth */

typedef void *pth_t;
typedef void *pth_mutex_t;
typedef void *pth_cond_t;
typedef void *pth_key_t;

typedef struct pth_attr_st {
  pth_t a_tid;
  int a_joinable;
} * pth_attr_t;

typedef struct pth_ringnode_st pth_ringnode_t;

struct pth_ringnode_st {
  pth_ringnode_t *rn_next;
  pth_ringnode_t *rn_prev;
};

typedef struct pth_ring_st {
  pth_ringnode_t *r_hook;
  unsigned int r_nodes;
} pth_ring_t;

typedef struct pth_msgport_st {
  pth_ring_t mp_queue;
  void *semaphore;
#ifdef __APPLE__
  char semaphore_name[64];
#endif
} * pth_msgport_t;

typedef struct pth_message_st {
  pth_ringnode_t m_node;
  pth_msgport_t m_replyport;
} pth_message_t;

typedef struct {
  unsigned tv_sec;
  unsigned tv_usec;
} pth_time_t;

typedef struct pth_event_st {
  long ev_type;
  union {
    pth_time_t tv;
    pth_msgport_t mp;
  };
} * pth_event_t;

#define PTH_ATTR_DEFAULT NULL
#define PTH_ATTR_JOINABLE 0
pth_attr_t pth_attr_new (void);
int pth_attr_destroy (pth_attr_t attr);
int pth_attr_init (pth_attr_t attr);
int pth_attr_get (pth_attr_t attr, int field, int *value);
int pth_attr_set (pth_attr_t attr, int field, int value);

pth_t pth_self (void);
pth_t pth_spawn (pth_attr_t attr, void *(*entry) (void *), void *arg);
int pth_join_ (pth_t tid, void **value);

int pth_mutex_init (pth_mutex_t *mutex);
int pth_mutex_destroy (pth_mutex_t *mutex);
int pth_mutex_acquire_ (pth_mutex_t *mutex, int nonblock, pth_event_t ev);
int pth_mutex_release (pth_mutex_t *mutex);

int pth_cond_init (pth_cond_t *cond);
int pth_cond_destroy (pth_cond_t *cond);
int pth_cond_await_ (pth_cond_t *cond, pth_mutex_t *mutex, pth_event_t ev);
int pth_cond_notify_ (pth_cond_t *cond, int broadcast);

#define PTH_EVENT_MSG 0
#define PTH_EVENT_TIME 1
#define PTH_FREE_THIS 0

pth_time_t pth_time (long sec, long usec);
pth_time_t pth_timeout (long sec, long usec);
pth_event_t pth_event (unsigned long spec, ...);
int pth_event_free (pth_event_t ev, int mode);
int pth_wait_ (pth_event_t ev);

pth_msgport_t pth_msgport_create (const char *name);
void pth_msgport_destroy (pth_msgport_t mp);
int pth_msgport_pending (pth_msgport_t mp);
int pth_msgport_put (pth_msgport_t mp, pth_message_t *m);
pth_message_t *pth_msgport_get (pth_msgport_t mp);
int pth_msgport_reply (pth_message_t *m);

int pth_key_create (pth_key_t *key, void (*func) (void *));
int pth_key_delete (pth_key_t key);
#define pth_key_getdata(key) sim_get_key_data (key)
#define pth_key_setdata(key, value) sim_set_key_data (key, value)
void *sim_get_key_data (pth_key_t key);
int sim_set_key_data (pth_key_t key, const void *value);

#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (! FALSE)
#endif

#include <sys/types.h> /* ssize_t */
#ifndef _WIN32
#include <sys/time.h>   /* struct timeval */
#include <sys/socket.h> /* struct sockaddr */
#include <sys/select.h> /* fd_set */
#include <poll.h>       /* struct pollfd */
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#endif

int pth_usleep_ (unsigned int usec);
unsigned int pth_sleep_ (unsigned int sec);
int pth_connect_ (int fd, const struct sockaddr *addr, socklen_t addrlen);
int pth_accept_ (int fd, struct sockaddr *addr, socklen_t *addrlen);
int pth_select_ (int nfd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout);
ssize_t pth_read_ (int fd, void *buf, size_t nbytes);
ssize_t pth_write_ (int fd, const void *buf, size_t nbytes);
ssize_t pth_recv_ (int fd, void *buf, size_t nbytes, int flags);
ssize_t pth_send_ (int fd, const void *buf, size_t nbytes, int flags);
#ifndef _WIN32
int pth_poll_ (struct pollfd *fds, unsigned nfd, int timeout);
int pth_recvmsg_ (int fd, struct msghdr *msg, int flags);
int pth_sendmsg_ (int fd, const struct msghdr *msg, int flags);
int pth_waitpid_ (pid_t pid, int *status, int options);
#define pth_fork fork
#define pth_get_handle(tid) ((pthread_t) (tid))
#else
void *pth_get_handle (pth_t tid);
#endif

void pth_unprotect (void);
void pth_protect_ (void);

#define PTH_UNPROTECT(CODE) (pth_unprotect (), (CODE))
#define PTH_PROTECT_(CODE) (pth_protect_ (), (CODE))
#define PTH_UNPROTECT_PROTECT_(CODE) (pth_unprotect (), (CODE), pth_protect_ ()) /* wrap any blocking function */

int pth_yield (pth_t tid);

int pth_init (void);
int pth_kill (void);

#endif /* HAVE_LIBPTH */

#define pth_mutex_try(mutex) pth_mutex_acquire_ (mutex, TRUE, NULL)

#ifdef __cplusplus
}
#endif

#endif
