/********************************************************************************
*										*
*    Thread functions. These try to duplicate the functionality of tForth.      * 
*										*
********************************************************************************/

int createthread (int tattr, int ssize, int addr, 
		  int arg, int flags, int IDaddr ) {			/* 236 */
    unsigned long result = _beginthreadex (
      (LPSECURITY_ATTRIBUTES) tattr,	// pointer to thread security attributes
      (DWORD) ssize,			// initial thread stack size, in bytes
      (LPTHREAD_START_ROUTINE) addr,	// pointer to thread function
      (LPVOID) arg,			// argument for new thread
      (DWORD) flags,			// creation flags
      (LPDWORD) IDaddr);	 	// pointer to returned thread identifier
    iserror = (result ? 0 : GetLastError());
    return (int)result;}

int exitthread (int code) {						/* 237 */
    _endthreadex (code); return iserror=0; }

int waitforAND (int addrh, int count) {					/* 238 */
    int result = WaitForMultipleObjects (
      (DWORD) count,			// number of handles in handle array 
      (CONST HANDLE *) addrh,		// address of object-handle array 
      TRUE,				// wait flag: wait for ALL threads to finish 
      INFINITE);			// time-out interval in milliseconds: for ever 
    iserror = (result == WAIT_FAILED) ? GetLastError() : 0;
    return result; }	

// Returns the array index of the object signaling first, -1 if the timer expired.
int waitforOR (int addrh, int count, int timeout) {			/* 239 */
    int result = WaitForMultipleObjects (
      (DWORD) count,			// number of handles in handle array 
      (CONST HANDLE *) addrh,		// address of object-handle array 
      FALSE,				// wait flag: wait for ANY threads to finish 
      (timeout == -1 ? INFINITE : timeout));
    iserror = (result == WAIT_FAILED) ? GetLastError() : 0;
    return (result == WAIT_TIMEOUT) ? -1 : result-WAIT_OBJECT_0; }

// A semaphore is simply an iForth VARIABLE .
int initCS (HANDLE *semaphore) {					/* 176 */
    *semaphore = CreateMutex(NULL,0,NULL);	
    return iserror=0; }	

// Waits for ownership of the specified mutex. 
int enterCS (HANDLE *semaphore) {					/* 177 */
    WaitForSingleObject( *semaphore, INFINITE );
    return iserror=0; }

// Releases ownership of the specified mutex. 
int leaveCS (HANDLE *semaphore) {					/* 178 */
    ReleaseMutex( *semaphore );
    return iserror=0; }	

// Links are blocking named pipes.
int createlink (char *name, int sz) {					/* 179 */
   HANDLE ret = CreateNamedPipe(
          makestr (name,sz),
 	  PIPE_ACCESS_DUPLEX | FILE_FLAG_WRITE_THROUGH,
          PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
	  1,		// maximum number of instances
	  4096,		// output buffer size, in bytes (disregarded)
	  4096, 	// input buffer size, in bytes (disregarded)
	  INFINITE,	// time-out time, in milliseconds
	  NULL);	// address of security attributes structure
   if (ret==INVALID_HANDLE_VALUE)  {iserror=GetLastError(); return 0;}
   iserror=0; return (int)ret; }

// Read can be done with readnamedpipe(char *buf, int sz, HANDLE h)	/* 233 */
// Write can be done with writenamedpipe(char *buf, int sz, HANDLE h)	/* 234 */
// Close is not needed. You can do it by calling closenamedpipe(h)	/* 235 */

int killthread(int h) {							/* 198 */
    iserror=0;
    return TerminateThread((HANDLE)h,0) ? 0 : GetLastError(); }

int closehandle (int h) {						/* 197 */
    int ret = CloseHandle((HANDLE)h) ? 0 : GetLastError();
    iserror = (ret != 0);
    return (int)ret; }

// This layout must match the one in iForth!
typedef struct channel {
  unsigned int id; 
  unsigned int name; 
  SOCKET lsock;
  SOCKET rsock;
  SOCKET wsock } channel;

int select4 (channel *addrs[], int count, int tim) {			/* 196 */ 
    struct timeval timeout;
    fd_set readfds; 
    int i,res;
    iserror=0;
    FD_ZERO(&readfds); 
    timeout.tv_sec=0; timeout.tv_usec=1000*tim;
    for (i=0; i<count; i++) 
	if (addrs[i] < (struct channel *)0xF0000000) 
	   FD_SET(addrs[i]->rsock,&readfds); 
    res=select(0,&readfds,NULL,NULL,&timeout);
    if (res==SOCKET_ERROR) {iserror = WSAGetLastError(); return -1;}
    if (res==0) return -1;	// timeout
    for (i=0; i<count; i++)
	if (addrs[i] < (struct channel *)0xF0000000)
	   if (FD_ISSET(addrs[i]->rsock,&readfds)) return i;
    iserror=WSATRY_AGAIN; return -1; }

/* EOF */