#include <gforth/0.7.9_20150820/libcc.h>
#include <pthread.h>
#if HAVE_MPROBE
#include <mcheck.h>
#endif
#include <limits.h>
#include <sys/mman.h>
#include <unistd.h>
#include <setjmp.h>
#include <stdio.h>
#include <signal.h>
#ifndef FIONREAD
#include <sys/socket.h>
#endif

#if HAVE_MPROBE
void gfpthread_abortmcheck(enum mcheck_status reason)
{
  if((int)reason > 0)
    longjmp(*(jmp_buf*)throw_jmp_handler,-2049-(int)reason);
}
#endif
void create_pipe(FILE ** addr)
{
  int epipe[2];
  pipe(epipe);
  addr[0]=fdopen(epipe[0], "r");
  addr[1]=fdopen(epipe[1], "a");
  setvbuf(addr[1], NULL, _IONBF, 0);
}
void *gforth_thread(user_area * t)
{
  Cell x;
  int throw_code;
  void *ip0=(void*)(t->save_task);
  sigset_t set;
  gforth_SP=(Cell*)(t->sp0);
  gforth_RP=(Cell*)(t->rp0);
  gforth_FP=(Float*)(t->fp0);
  gforth_LP=(Address)(t->lp0);
  gforth_UP=t;

  *--gforth_SP=(Cell)t;

#if HAVE_MPROBE
  /* mcheck(gfpthread_abortmcheck); */
#endif
  pthread_cleanup_push((void (*)(void*))gforth_free_stacks, (void*)t);
  gforth_sigset(&set, SIGINT, SIGQUIT, SIGTERM, 0);
  pthread_sigmask(SIG_BLOCK, &set, NULL);
  x=gforth_go(ip0);
  pthread_cleanup_pop(1);
  pthread_exit((void*)x);
}
static inline void *gforth_thread_p()
{
  return (void*)&gforth_thread;
}
static inline void *pthread_plus(void * thread)
{
  return thread+sizeof(pthread_t);
}
static inline Cell pthreads(Cell thread)
{
  return thread*(int)sizeof(pthread_t);
}
static inline void *pthread_mutex_plus(void * thread)
{
  return thread+sizeof(pthread_mutex_t);
}
static inline Cell pthread_mutexes(Cell thread)
{
  return thread*(int)sizeof(pthread_mutex_t);
}
static inline void *pthread_cond_plus(void * thread)
{
  return thread+sizeof(pthread_cond_t);
}
static inline Cell pthread_conds(Cell thread)
{
  return thread*(int)sizeof(pthread_cond_t);
}
pthread_attr_t * pthread_detach_attr(void)
{
  static pthread_attr_t attr;
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  return &attr;
}
#include <sys/ioctl.h>
#include <errno.h>
int check_read(FILE * fid)
{
  int pipe = fileno(fid);
  int chars_avail;
  int result = ioctl(pipe, FIONREAD, &chars_avail);
  return (result==-1) ? -errno : chars_avail;
}
#include <poll.h>
int wait_read(FILE * fid, Cell timeoutns, Cell timeouts)
{
  struct pollfd fds = { fileno(fid), POLLIN, 0 };
#if defined(linux) && !defined(__ANDROID__)
  struct timespec tout = { timeouts, timeoutns };
  ppoll(&fds, 1, &tout, 0);
#else
  poll(&fds, 1, timeoutns/1000000+timeouts*1000);
#endif
  return check_read(fid);
}
/* optional: CPU affinity */
#include <sched.h>
int stick_to_core(int core_id) {
#ifdef HAVE_PTHREAD_SETAFFINITY_NP
  cpu_set_t cpuset;

  core_id %= sysconf(_SC_NPROCESSORS_ONLN);
    return EINVAL;
  
  CPU_ZERO(&cpuset);
  CPU_SET(core_id, &cpuset);
  
  return pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
#else
  return 0;
#endif
}
ptrpair libgfpthread_LTX_gforth_c_pthread_plus_a_a(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=0, farg0=-1;
  sp[0]=(Cell)pthread_plus((void *)(sp[0]));
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_pthreads_n_n(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=0, farg0=-1;
  sp[0]=pthreads(sp[0]);
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_gforth_thread_p__a(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=-1, farg0=-1;
  sp[-1]=(Cell)gforth_thread_p();
  x.sp = sp+-1;
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_gforth_stacks_nnnn_a(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=3, farg0=-1;
  sp[3]=(Cell)gforth_stacks(sp[3],sp[2],sp[1],sp[0]);
  x.sp = sp+3;
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_pthread_create_aaaa_n(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=3, farg0=-1;
  sp[3]=pthread_create((pthread_t*)(sp[3]),(void *)(sp[2]),(void *)(sp[1]),(void *)(sp[0]));
  x.sp = sp+3;
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_pthread_exit_a_v(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=0, farg0=-1;
  pthread_exit((void *)(sp[0]));
  x.sp = sp+1;
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_pthread_kill_an_n(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=1, farg0=-1;
  sp[1]=pthread_kill(*(pthread_t*)(sp[1]),sp[0]);
  x.sp = sp+1;
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_pthread_cancel_a_n(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=0, farg0=-1;
  sp[0]=pthread_cancel(*(pthread_t*)(sp[0]));
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_pthread_mutex_init_aa_n(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=1, farg0=-1;
  sp[1]=pthread_mutex_init((void *)(sp[1]),(void *)(sp[0]));
  x.sp = sp+1;
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_pthread_mutex_destroy_a_n(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=0, farg0=-1;
  sp[0]=pthread_mutex_destroy((void *)(sp[0]));
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_pthread_mutex_lock_a_n(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=0, farg0=-1;
  sp[0]=pthread_mutex_lock((void *)(sp[0]));
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_pthread_mutex_unlock_a_n(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=0, farg0=-1;
  sp[0]=pthread_mutex_unlock((void *)(sp[0]));
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_pthread_mutex_plus_a_a(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=0, farg0=-1;
  sp[0]=(Cell)pthread_mutex_plus((void *)(sp[0]));
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_pthread_mutexes_n_n(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=0, farg0=-1;
  sp[0]=pthread_mutexes(sp[0]);
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_pthread_cond_plus_a_a(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=0, farg0=-1;
  sp[0]=(Cell)pthread_cond_plus((void *)(sp[0]));
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_pthread_conds_n_n(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=0, farg0=-1;
  sp[0]=pthread_conds(sp[0]);
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_sched_yield__v(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=-1, farg0=-1;
  sched_yield();
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_pthread_detach_attr__a(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=-1, farg0=-1;
  sp[-1]=(Cell)pthread_detach_attr();
  x.sp = sp+-1;
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_pthread_cond_signal_a_n(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=0, farg0=-1;
  sp[0]=pthread_cond_signal((void *)(sp[0]));
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_pthread_cond_broadcast_a_n(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=0, farg0=-1;
  sp[0]=pthread_cond_broadcast((void *)(sp[0]));
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_pthread_cond_wait_aa_n(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=1, farg0=-1;
  sp[1]=pthread_cond_wait((void *)(sp[1]),(void *)(sp[0]));
  x.sp = sp+1;
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_pthread_cond_timedwait_aaa_n(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=2, farg0=-1;
  sp[2]=pthread_cond_timedwait((void *)(sp[2]),(void *)(sp[1]),(void *)(sp[0]));
  x.sp = sp+2;
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_create_pipe_a_v(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=0, farg0=-1;
  create_pipe((void *)(sp[0]));
  x.sp = sp+1;
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_check_read_a_n(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=0, farg0=-1;
  sp[0]=check_read((void *)(sp[0]));
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_wait_read_ann_n(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=2, farg0=-1;
  sp[2]=wait_read((void *)(sp[2]),sp[1],sp[0]);
  x.sp = sp+2;
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_getpid__n(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=-1, farg0=-1;
  sp[-1]=getpid();
  x.sp = sp+-1;
  return x;
}
ptrpair libgfpthread_LTX_gforth_c_stick_to_core_n_n(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=0, farg0=-1;
  sp[0]=stick_to_core(sp[0]);
  return x;
}
#define get_pthread_id(addr) *(pthread_t*)(addr) = pthread_self()
ptrpair libgfpthread_LTX_gforth_c_get_pthread_id_a_v(GFORTH_ARGS)
{
  Cell MAYBE_UNUSED *sp = x.sp;
  Float MAYBE_UNUSED *fp = x.fp;
  int MAYBE_UNUSED arg0=0, farg0=-1;
  get_pthread_id((void *)(sp[0]));
  x.sp = sp+1;
  return x;
}
hash_128 gflibcc_hash_pthread = "\x18\x3B\x14\x98\x43\x7D\xC7\x0C\x9B\xD4\x5B\x3C\xCE\x76\x34\x1A";
