291 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			291 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/*  $Id$
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Part of SWI-Prolog
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Author:        Jan Wielemaker
							 | 
						||
| 
								 | 
							
								    E-mail:        jan@swi.psy.uva.nl
							 | 
						||
| 
								 | 
							
								    WWW:           http://www.swi-prolog.org
							 | 
						||
| 
								 | 
							
								    Copyright (C): 1985-2004, University of Amsterdam
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This program 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; either version 2
							 | 
						||
| 
								 | 
							
								    of the License, or (at your option) any later version.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This program 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 Lesser General Public
							 | 
						||
| 
								 | 
							
								    License along with this library; if not, write to the Free Software
							 | 
						||
| 
								 | 
							
								    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    As a special exception, if you link this library with other files,
							 | 
						||
| 
								 | 
							
								    compiled with a Free Software compiler, to produce an executable, this
							 | 
						||
| 
								 | 
							
								    library does not by itself cause the resulting executable to be covered
							 | 
						||
| 
								 | 
							
								    by the GNU General Public License. This exception does not however
							 | 
						||
| 
								 | 
							
								    invalidate any other reasons why the executable file might be covered by
							 | 
						||
| 
								 | 
							
								    the GNU General Public License.
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <SWI-Stream.h>
							 | 
						||
| 
								 | 
							
								#include <SWI-Prolog.h>
							 | 
						||
| 
								 | 
							
								#include <errno.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef __WINDOWS__
							 | 
						||
| 
								 | 
							
								#include <windows.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
							 | 
						||
| 
								 | 
							
								This file provides a windows alternative to   an anonymous pipe that can
							 | 
						||
| 
								 | 
							
								be waited for in the same pool as sockets using by tcp_select/3. It is a
							 | 
						||
| 
								 | 
							
								work-around that allows a socket-based server  using tcp_select/3 for IO
							 | 
						||
| 
								 | 
							
								multiplexing  to  create  an  additional    communication   channal  for
							 | 
						||
| 
								 | 
							
								controlling the server.
							 | 
						||
| 
								 | 
							
								- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define PIPE_MAGIC	0x6b3a914cL
							 | 
						||
| 
								 | 
							
								#define ISPIPE(p)	if ( p->magic != PIPE_MAGIC ) \
							 | 
						||
| 
								 | 
							
											{ errno = EINVAL; \
							 | 
						||
| 
								 | 
							
											  return -1; \
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								typedef struct pipe
							 | 
						||
| 
								 | 
							
								{ long	magic;				/* magic code */
							 | 
						||
| 
								 | 
							
								  int   size;				/* size of the pipe */
							 | 
						||
| 
								 | 
							
								  char *buf;				/* Buffer */
							 | 
						||
| 
								 | 
							
								  int   in;
							 | 
						||
| 
								 | 
							
								  int   out;
							 | 
						||
| 
								 | 
							
								  int   writers;			/* write open count */
							 | 
						||
| 
								 | 
							
								  int   readers;			/* read open count */
							 | 
						||
| 
								 | 
							
								  int	blocking;			/* pipe is blocking */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  CRITICAL_SECTION mutex;
							 | 
						||
| 
								 | 
							
								  HANDLE event;				/* signal if data is available */
							 | 
						||
| 
								 | 
							
								} pipe;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static pipe *
							 | 
						||
| 
								 | 
							
								create_pipe(int size, int blocking)
							 | 
						||
| 
								 | 
							
								{ pipe *p = PL_malloc(sizeof(*p));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  p->buf  = PL_malloc(size);
							 | 
						||
| 
								 | 
							
								  p->size = size;
							 | 
						||
| 
								 | 
							
								  p->in = p->out = 0;
							 | 
						||
| 
								 | 
							
								  p->readers = p->writers = 0;
							 | 
						||
| 
								 | 
							
								  p->blocking = blocking;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  InitializeCriticalSection(&p->mutex);
							 | 
						||
| 
								 | 
							
								  p->event = CreateEvent(NULL, FALSE, FALSE, NULL);
							 | 
						||
| 
								 | 
							
								  p->magic = PIPE_MAGIC;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return p;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								destroy_pipe(pipe *p)
							 | 
						||
| 
								 | 
							
								{ ISPIPE(p);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  EnterCriticalSection(&p->mutex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  PL_free(p->buf);
							 | 
						||
| 
								 | 
							
								  CloseHandle(p->event);
							 | 
						||
| 
								 | 
							
								  LeaveCriticalSection(&p->mutex);
							 | 
						||
| 
								 | 
							
								  DeleteCriticalSection(&p->mutex);
							 | 
						||
| 
								 | 
							
								  p->magic = 0;
							 | 
						||
| 
								 | 
							
								  PL_free(p);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								write_pipe(pipe *pipe, char *buf, int size)
							 | 
						||
| 
								 | 
							
								{ ISPIPE(pipe);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  EnterCriticalSection(&pipe->mutex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for(;;)
							 | 
						||
| 
								 | 
							
								  { if ( pipe->in + size <= pipe->size )
							 | 
						||
| 
								 | 
							
								    { memcpy(pipe->buf+pipe->in, buf, size);
							 | 
						||
| 
								 | 
							
								      pipe->in += size;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      SetEvent(pipe->event);
							 | 
						||
| 
								 | 
							
								      LeaveCriticalSection(&pipe->mutex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return size;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ( pipe->out > 0 )
							 | 
						||
| 
								 | 
							
								    { memmove(pipe->buf, pipe->buf+pipe->out, pipe->in - pipe->out);
							 | 
						||
| 
								 | 
							
								      pipe->in -= pipe->out;
							 | 
						||
| 
								 | 
							
								      pipe->out = 0;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ( size > pipe->size )
							 | 
						||
| 
								 | 
							
								      size = pipe->size;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
							 | 
						||
| 
								 | 
							
								Non-blocking read from our pipe.
							 | 
						||
| 
								 | 
							
								- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								read_pipe(pipe *pipe, char *buf, int size)
							 | 
						||
| 
								 | 
							
								{ int avail;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ISPIPE(pipe);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								retry:
							 | 
						||
| 
								 | 
							
								  EnterCriticalSection(&pipe->mutex);
							 | 
						||
| 
								 | 
							
								  avail = pipe->in - pipe->out;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( avail > 0 )
							 | 
						||
| 
								 | 
							
								  { if ( size < avail )
							 | 
						||
| 
								 | 
							
								      avail = size;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    memcpy(buf, pipe->buf+pipe->out, avail);
							 | 
						||
| 
								 | 
							
								    pipe->out += avail;
							 | 
						||
| 
								 | 
							
								    if ( pipe->in == pipe->out )
							 | 
						||
| 
								 | 
							
								      pipe->in = pipe->out = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    LeaveCriticalSection(&pipe->mutex);
							 | 
						||
| 
								 | 
							
								    return avail;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( pipe->writers == 0 )
							 | 
						||
| 
								 | 
							
								  { LeaveCriticalSection(&pipe->mutex);
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( pipe->blocking )
							 | 
						||
| 
								 | 
							
								  { int rc;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    LeaveCriticalSection(&pipe->mutex);
							 | 
						||
| 
								 | 
							
								    rc = MsgWaitForMultipleObjects(1,
							 | 
						||
| 
								 | 
							
												   &pipe->event,
							 | 
						||
| 
								 | 
							
												   FALSE,	/* wait for either event */
							 | 
						||
| 
								 | 
							
												   INFINITE,
							 | 
						||
| 
								 | 
							
												   QS_ALLINPUT);
							 | 
						||
| 
								 | 
							
								    if ( rc == WAIT_OBJECT_0+1 )	/* message arrived */
							 | 
						||
| 
								 | 
							
								    { MSG msg;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
							 | 
						||
| 
								 | 
							
								      { TranslateMessage(&msg);
							 | 
						||
| 
								 | 
							
									DispatchMessage(&msg);
							 | 
						||
| 
								 | 
							
									if ( PL_handle_signals() < 0 )
							 | 
						||
| 
								 | 
							
									{ errno = EINTR;		/* exception */
							 | 
						||
| 
								 | 
							
									  return -1;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    goto retry;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  errno = EWOULDBLOCK;
							 | 
						||
| 
								 | 
							
								  LeaveCriticalSection(&pipe->mutex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return -1;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								reader_close_pipe(pipe *p)
							 | 
						||
| 
								 | 
							
								{ ISPIPE(p);
							 | 
						||
| 
								 | 
							
								  p->readers--;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( p->readers <= 0 && p->writers <= 0 )
							 | 
						||
| 
								 | 
							
								    return destroy_pipe(p);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								writer_close_pipe(pipe *p)
							 | 
						||
| 
								 | 
							
								{ ISPIPE(p);
							 | 
						||
| 
								 | 
							
								  p->writers--;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( p->readers <= 0 && p->writers <= 0 )
							 | 
						||
| 
								 | 
							
								    return destroy_pipe(p);
							 | 
						||
| 
								 | 
							
								  if ( p->writers <= 0 )
							 | 
						||
| 
								 | 
							
								  { SetEvent(p->event);			/* Signal EOF */
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static IOFUNCTIONS pipe_read_functions =
							 | 
						||
| 
								 | 
							
								{ (Sread_function)    read_pipe,
							 | 
						||
| 
								 | 
							
								  (Swrite_function)   write_pipe,
							 | 
						||
| 
								 | 
							
								  (Sseek_function)    0,
							 | 
						||
| 
								 | 
							
								  (Sclose_function)   reader_close_pipe,
							 | 
						||
| 
								 | 
							
								  (Scontrol_function) 0
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static IOFUNCTIONS pipe_write_functions =
							 | 
						||
| 
								 | 
							
								{ (Sread_function)    read_pipe,
							 | 
						||
| 
								 | 
							
								  (Swrite_function)   write_pipe,
							 | 
						||
| 
								 | 
							
								  (Sseek_function)    0,
							 | 
						||
| 
								 | 
							
								  (Sclose_function)   writer_close_pipe,
							 | 
						||
| 
								 | 
							
								  (Scontrol_function) 0
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static foreign_t
							 | 
						||
| 
								 | 
							
								tcp_pipe(term_t in, term_t out)
							 | 
						||
| 
								 | 
							
								{ pipe *p = create_pipe(4096, TRUE);
							 | 
						||
| 
								 | 
							
								  IOSTREAM *sin, *sout;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  sin  = Snew(p, SIO_FBUF|SIO_INPUT|SIO_RECORDPOS,  &pipe_read_functions);
							 | 
						||
| 
								 | 
							
								  p->readers++;
							 | 
						||
| 
								 | 
							
								  sout = Snew(p, SIO_FBUF|SIO_OUTPUT|SIO_RECORDPOS, &pipe_write_functions);
							 | 
						||
| 
								 | 
							
								  p->writers++;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( !PL_unify_stream(in, sin) ||
							 | 
						||
| 
								 | 
							
								       !PL_unify_stream(out, sout) )
							 | 
						||
| 
								 | 
							
								  { Sclose(sin);
							 | 
						||
| 
								 | 
							
								    Sclose(sout);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return FALSE;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return TRUE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#else /*__WINDOWS__*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static foreign_t
							 | 
						||
| 
								 | 
							
								tcp_pipe(term_t Read, term_t Write)
							 | 
						||
| 
								 | 
							
								{ int fd[2];
							 | 
						||
| 
								 | 
							
								  IOSTREAM *in, *out;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( pipe(fd) != 0 )
							 | 
						||
| 
								 | 
							
								    return pl_error("pipe", 2, NULL, ERR_ERRNO, errno, "create", "pipe", 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  in  = Sfdopen(fd[0], "r");
							 | 
						||
| 
								 | 
							
								  out = Sfdopen(fd[1], "w");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ( PL_unify_stream(Read, in) &&
							 | 
						||
| 
								 | 
							
								       PL_unify_stream(Write, out) )
							 | 
						||
| 
								 | 
							
								    return TRUE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  Sclose(in);
							 | 
						||
| 
								 | 
							
								  Sclose(out);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return FALSE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif /*__WINDOWS__*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								install_t
							 | 
						||
| 
								 | 
							
								install_winpipe()
							 | 
						||
| 
								 | 
							
								{ PL_register_foreign("tcp_pipe", 2, tcp_pipe, 0);
							 | 
						||
| 
								 | 
							
								}
							 |