e576bb2002-10-11Martin Nilsson /* || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information.
7b62e22011-04-25Martin Stjernholm || $Id$
e576bb2002-10-11Martin Nilsson */
a2ca6d1998-06-12Fredrik Noring #include "global.h"
3c39d01997-10-05Per Hedbor #include "config.h"
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #include "machine.h"
51ef5c2002-10-21Marcus Comstedt #include "module.h"
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  #include <sys/types.h> #include <sys/stat.h>
d1c3001998-05-17Henrik Grubbström (Grubba) #ifdef HAVE_SYS_FILE_H #include <sys/file.h> #endif /* HAVE_SYS_FILE_H */
1aac001997-05-22Henrik Grubbström (Grubba) #include <errno.h>
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #ifdef HAVE_SYS_MMAN_H #include <sys/mman.h> #else #ifdef HAVE_LINUX_MMAN_H #include <linux/mman.h> #else #ifdef HAVE_MMAP /* sys/mman.h is _probably_ there anyway. */ #include <sys/mman.h> #endif #endif #endif
3e3a992000-08-17Henrik Grubbström (Grubba) #ifdef HAVE_SYS_ID_H #include <sys/id.h> #endif /* HAVE_SYS_ID_H */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #include <fcntl.h>
7b62e22011-04-25Martin Stjernholm RCSID("$Id$");
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
3c39d01997-10-05Per Hedbor #include "threads.h"
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #include "stralloc.h"
bb55f81997-03-16Fredrik Hübinette (Hubbe) #include "pike_macros.h"
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #include "object.h" #include "constants.h" #include "interpret.h" #include "svalue.h"
b2d3e42000-12-01Fredrik Hübinette (Hubbe) #include "pike_error.h"
9c6f7d1997-04-15Fredrik Hübinette (Hubbe) #include "builtin_functions.h"
8c461c2000-07-02Henrik Grubbström (Grubba) #include "fdlib.h"
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  #ifndef S_ISREG #ifdef S_IFREG #define S_ISREG(mode) (((mode) & (S_IFMT)) == (S_IFREG)) #else #define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG)) #endif #endif
6dc2772000-07-28Fredrik Hübinette (Hubbe) 
6ad2372002-05-11Martin Nilsson #define sp Pike_sp
6dc2772000-07-28Fredrik Hübinette (Hubbe) 
ab6aec1997-02-11Fredrik Hübinette (Hubbe) /* #define PIPE_STRING_DEBUG #define PIPE_MMAP_DEBUG #define PIPE_FILE_DEBUG #define BLOCKING_CLOSE */
169c541998-05-17Henrik Grubbström (Grubba) #ifndef SEEK_SET
d1c3001998-05-17Henrik Grubbström (Grubba) #ifdef L_SET #define SEEK_SET L_SET #else /* !L_SET */
169c541998-05-17Henrik Grubbström (Grubba) #define SEEK_SET 0
d1c3001998-05-17Henrik Grubbström (Grubba) #endif /* L_SET */
169c541998-05-17Henrik Grubbström (Grubba) #endif /* SEEK_SET */ #ifndef SEEK_CUR
d1c3001998-05-17Henrik Grubbström (Grubba) #ifdef L_INCR
b6cef11998-10-23Henrik Grubbström (Grubba) #define SEEK_CUR L_INCR
d1c3001998-05-17Henrik Grubbström (Grubba) #else /* !L_INCR */
169c541998-05-17Henrik Grubbström (Grubba) #define SEEK_CUR 1
d1c3001998-05-17Henrik Grubbström (Grubba) #endif /* L_INCR */
169c541998-05-17Henrik Grubbström (Grubba) #endif /* SEEK_CUR */ #ifndef SEEK_END
d1c3001998-05-17Henrik Grubbström (Grubba) #ifdef L_XTND #define SEEK_END L_XTND #else /* !L_XTND */
169c541998-05-17Henrik Grubbström (Grubba) #define SEEK_END 2
d1c3001998-05-17Henrik Grubbström (Grubba) #endif /* L_XTND */
169c541998-05-17Henrik Grubbström (Grubba) #endif /* SEEK_END */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #if 0 #define INSISTANT_WRITE #endif #ifndef MAP_FILE # define MAP_FILE 0 #endif
3c39d01997-10-05Per Hedbor #define READ_BUFFER_SIZE 65536
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #define MAX_BYTES_IN_BUFFER 65536 /* * usage: * single socket output * or regular file output and (multiple, adding) socket output * with no mmap input * * multiple socket output without regular file output illegal */ static struct program *pipe_program, *output_program;
b1f4eb1998-01-13Fredrik Hübinette (Hubbe) #ifdef THIS #undef THIS #endif
a315182000-07-07Henrik Grubbström (Grubba) #define THIS ((struct pipe *)(Pike_fp->current_storage)) #define THISOBJ (Pike_fp->current_object)
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  struct input {
dc16b41998-04-03Henrik Grubbström (Grubba)  enum { I_NONE,I_OBJ,I_BLOCKING_OBJ,I_STRING,I_MMAP } type;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  union { struct object *obj; struct pike_string *str; char *mmap; } u;
4cad852000-08-03Henrik Grubbström (Grubba)  size_t len; /* current input: string or mmap len */ ptrdiff_t set_blocking_offset, set_nonblocking_offset;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  struct input *next; }; struct output { struct object *obj;
4cad852000-08-03Henrik Grubbström (Grubba)  ptrdiff_t write_offset, set_blocking_offset, set_nonblocking_offset;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  int fd; enum { O_RUN, /* waiting for callback */ O_SLEEP /* sleeping; waiting for more data */ } mode;
4cad852000-08-03Henrik Grubbström (Grubba)  size_t pos; /* position in buffer */
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  struct object *next; struct pipe *the_pipe; }; struct buffer { struct pike_string *s; struct buffer *next; }; struct pipe { int living_outputs; /* number of output objects */ struct svalue done_callback; struct svalue output_closed_callback; struct svalue id; /* * if fd is -1: use fd * else firstinput's type is I_MMAP: use firstinput's mmap * else use buffer */ int fd; /* buffer fd or -1 */ unsigned long bytes_in_buffer;
b96ca92000-08-19Henrik Grubbström (Grubba)  size_t pos;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  /* fd: size of buffer file */ /* current position of first element (buffer or mmap) */ struct buffer *firstbuffer,*lastbuffer; short sleeping; /* sleeping; buffer is full */ short done; struct input *firstinput,*lastinput; struct object *firstoutput;
a4dbbb1997-08-29Marcus Comstedt  unsigned long sent;
ab6aec1997-02-11Fredrik Hübinette (Hubbe) };
4cad852000-08-03Henrik Grubbström (Grubba) static ptrdiff_t offset_input_read_callback; static ptrdiff_t offset_input_close_callback; static ptrdiff_t offset_output_write_callback; static ptrdiff_t offset_output_close_callback; static ptrdiff_t mmapped, nobjects, nstrings, noutputs; static ptrdiff_t ninputs, nbuffers, sbuffers;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  void close_and_free_everything(struct object *o,struct pipe *); static INLINE void output_finish(struct object *obj); static INLINE void output_try_write_some(struct object *obj); /********** internal ********************************************************/ /* Push a callback to this object given the internal function number. */
d098b22000-08-09Henrik Grubbström (Grubba) static void push_callback(ptrdiff_t no)
ab6aec1997-02-11Fredrik Hübinette (Hubbe) {
a315182000-07-07Henrik Grubbström (Grubba)  add_ref(Pike_sp->u.object=THISOBJ);
d098b22000-08-09Henrik Grubbström (Grubba)  Pike_sp->subtype = DO_NOT_WARN(no + Pike_fp->context.identifier_level); Pike_sp->type = T_FUNCTION;
a315182000-07-07Henrik Grubbström (Grubba)  Pike_sp++;
ab6aec1997-02-11Fredrik Hübinette (Hubbe) } /* Allocate a new struct input, link it last in the linked list */ static INLINE struct input *new_input(void) { struct input *i; ninputs++; i=ALLOC_STRUCT(input); i->type=I_NONE; i->next=NULL; if (THIS->lastinput) THIS->lastinput->next=i; else THIS->firstinput=i; THIS->lastinput=i; return i; } /* Free an input struct and all that it stands for */ static INLINE void free_input(struct input *i) {
1047302000-08-28Fredrik Hübinette (Hubbe)  debug_malloc_touch(i);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  ninputs--; switch (i->type) { case I_OBJ:
dc16b41998-04-03Henrik Grubbström (Grubba)  case I_BLOCKING_OBJ:
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if (!i->u.obj) break; if (i->u.obj->prog) { #ifdef BLOCKING_CLOSE apply_low(i->u.obj,i->set_blocking_offset,0); pop_stack(); #endif apply(i->u.obj,"close",0); pop_stack(); destruct(i->u.obj); } free_object(i->u.obj); nobjects--; i->u.obj=0; break; case I_STRING: free_string(i->u.str); nstrings--; break; case I_MMAP: #if defined(HAVE_MMAP) && defined(HAVE_MUNMAP) munmap(i->u.mmap,i->len); mmapped -= i->len; #else
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("I_MMAP input when MMAP is diabled!");
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #endif break;
9c6f7d1997-04-15Fredrik Hübinette (Hubbe)  case I_NONE: break;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  } free((char *)i); } /* do the done_callback, then close and free everything */ static INLINE void pipe_done(void) { if (THIS->done_callback.type!=T_INT) { assign_svalue_no_free(sp++,&THIS->id); apply_svalue(&(THIS->done_callback),1); pop_stack(); if(!THISOBJ->prog) /* We will not free anything in this case. */ return;
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  /* Pike_error("Pipe done callback destructed pipe.\n"); */
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  } close_and_free_everything(THISOBJ,THIS); } static void finished_p(void) { if(THIS->done) return; if(THIS->fd != -1) { if(THIS->living_outputs > 1) return; if(THIS->firstinput) return; }else{ if(THIS->living_outputs) return; } pipe_done(); } /* Allocate a new buffer and put it at the end of the chain of buffers * scheduled for output. Return 1 if we have more bytes in buffers * than allowed afterwards. */ static INLINE int append_buffer(struct pike_string *s) /* 1=buffer full */ { struct buffer *b;
1047302000-08-28Fredrik Hübinette (Hubbe)  debug_malloc_touch(s);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if(THIS->fd!= -1) {
8c461c2000-07-02Henrik Grubbström (Grubba)  fd_lseek(THIS->fd, THIS->pos, SEEK_SET); fd_write(THIS->fd, s->str, s->len);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  THIS->pos+=s->len; return 0; } else { nbuffers++; b=ALLOC_STRUCT(buffer); b->next=NULL; b->s=s; sbuffers += s->len;
d6ac731998-04-20Henrik Grubbström (Grubba)  add_ref(s);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if (THIS->lastbuffer) THIS->lastbuffer->next=b; else THIS->firstbuffer=b; THIS->lastbuffer=b; THIS->bytes_in_buffer+=s->len; } return THIS->bytes_in_buffer > MAX_BYTES_IN_BUFFER; } /* Wake up the sleepers */
be478c1997-08-30Henrik Grubbström (Grubba) static void low_start(void)
ab6aec1997-02-11Fredrik Hübinette (Hubbe) { struct object *obj, *next; struct output *o;
d6ac731998-04-20Henrik Grubbström (Grubba)  add_ref(THISOBJ); /* dont kill yourself now */
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  for(obj=THIS->firstoutput;obj;obj=next) {
2304231999-03-05Henrik Grubbström (Grubba)  /* add_ref(obj); */ /* Hang on PLEASE!! /hubbe */
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  o=(struct output *)(obj->storage);
ce3f4d1999-03-05Wilhelm Köhler  next=o->next;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if (o->obj && o->mode==O_SLEEP) { if (!o->obj->prog) { output_finish(obj); } else { push_int(0); push_callback(offset_output_write_callback); push_callback(offset_output_close_callback); apply_low(o->obj,o->set_nonblocking_offset,3);
ce3f4d1999-03-05Wilhelm Köhler  /* output_try_write_some(obj); */
2304231999-03-05Henrik Grubbström (Grubba)  /* o->mode=O_RUN; */ /* Hubbe */
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  } }
ce3f4d1999-03-05Wilhelm Köhler  /* next=o->next; */ /* free_object(obj); */
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  } free_object(THISOBJ); }
7dd0c61998-04-03Henrik Grubbström (Grubba) /* Read some data from the blocking object. * */ static int read_some_data(void) { struct pipe *this = THIS; struct input * i = this->firstinput; if (!i || i->type != I_BLOCKING_OBJ) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("PIPE: read_some_data(): Bad input type!\n");
a4cbce1998-04-06Fredrik Hübinette (Hubbe)  return -1;
7dd0c61998-04-03Henrik Grubbström (Grubba)  } push_int(8192); push_int(1); /* We don't care if we don't get all 8192 bytes. */ apply(i->u.obj, "read", 2); if ((sp[-1].type == T_STRING) && (sp[-1].u.string->len > 0)) { append_buffer(sp[-1].u.string); pop_stack(); THIS->sleeping = 1; return(1); /* Success */ } /* FIXME: Should we check the return value here? */ pop_stack(); /* EOF */ return(0); /* EOF */ }
ab6aec1997-02-11Fredrik Hübinette (Hubbe) /* Let's guess what this function does.... * */ static INLINE void input_finish(void) { struct input *i; while(1) {
dc16b41998-04-03Henrik Grubbström (Grubba)  /* Get the next input from the queue */
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  i=THIS->firstinput->next; free_input(THIS->firstinput); THIS->firstinput=i; if(!i) break; switch(i->type) { case I_OBJ: THIS->sleeping=0; push_callback(offset_input_read_callback); push_int(0); push_callback(offset_input_close_callback); apply_low(i->u.obj,i->set_nonblocking_offset,3); pop_stack(); return;
dc16b41998-04-03Henrik Grubbström (Grubba)  case I_BLOCKING_OBJ:
7dd0c61998-04-03Henrik Grubbström (Grubba)  if (read_some_data())
dc16b41998-04-03Henrik Grubbström (Grubba)  return;
7dd0c61998-04-03Henrik Grubbström (Grubba)  continue;
dc16b41998-04-03Henrik Grubbström (Grubba) 
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  case I_MMAP: if (THIS->fd==-1) return; continue; case I_STRING: append_buffer(i->u.str);
9c6f7d1997-04-15Fredrik Hübinette (Hubbe)  case I_NONE: break;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  } } THIS->sleeping=0; low_start(); finished_p(); } /* This function reads some data from the file cache.. * Called when we want some data to send. */
d098b22000-08-09Henrik Grubbström (Grubba) static INLINE struct pike_string* gimme_some_data(size_t pos)
ab6aec1997-02-11Fredrik Hübinette (Hubbe) { struct buffer *b;
d098b22000-08-09Henrik Grubbström (Grubba)  ptrdiff_t len;
8c2ec71997-10-10Henrik Grubbström (Grubba)  struct pipe *this = THIS;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  /* We have a file cache, read from it */
3c39d01997-10-05Per Hedbor  if (this->fd!=-1)
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  {
3c39d01997-10-05Per Hedbor  char buffer[READ_BUFFER_SIZE]; if (this->pos<=pos) return NULL; /* no data */ len=this->pos-pos;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if (len>READ_BUFFER_SIZE) len=READ_BUFFER_SIZE;
3c39d01997-10-05Per Hedbor  THREADS_ALLOW();
8c461c2000-07-02Henrik Grubbström (Grubba)  fd_lseek(this->fd, pos, SEEK_SET);
3c39d01997-10-05Per Hedbor  THREADS_DISALLOW();
1aac001997-05-22Henrik Grubbström (Grubba)  do {
3c39d01997-10-05Per Hedbor  THREADS_ALLOW();
8c461c2000-07-02Henrik Grubbström (Grubba)  len = fd_read(this->fd, buffer, len);
3c39d01997-10-05Per Hedbor  THREADS_DISALLOW();
1aac001997-05-22Henrik Grubbström (Grubba)  if (len < 0) { if (errno != EINTR) { return(NULL); }
700dac2002-02-05Martin Stjernholm  check_threads_etc();
1aac001997-05-22Henrik Grubbström (Grubba)  } } while(len < 0);
fef91a1998-07-22Henrik Grubbström (Grubba)  /* * FIXME: What if len is 0? */
3c39d01997-10-05Per Hedbor  return make_shared_binary_string(buffer,len);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  }
3c39d01997-10-05Per Hedbor  if (pos<this->pos)
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  return make_shared_string("buffer underflow"); /* shit */ /* We want something in the next buffer */
3c39d01997-10-05Per Hedbor  while (this->firstbuffer && pos>=this->pos+this->firstbuffer->s->len)
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  { /* Free the first buffer, and update THIS->pos */
3c39d01997-10-05Per Hedbor  b=this->firstbuffer; this->pos+=b->s->len; this->bytes_in_buffer-=b->s->len; this->firstbuffer=b->next;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if (!b->next)
3c39d01997-10-05Per Hedbor  this->lastbuffer=NULL;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  sbuffers-=b->s->len; nbuffers--; free_string(b->s); free((char *)b); /* Wake up first input if it was sleeping and we * have room for more in the buffer. */
3c39d01997-10-05Per Hedbor  if (this->sleeping && this->firstinput && this->bytes_in_buffer<MAX_BYTES_IN_BUFFER)
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  {
eb7d4c1998-04-03Henrik Grubbström (Grubba)  if (this->firstinput->type == I_BLOCKING_OBJ) {
7dd0c61998-04-03Henrik Grubbström (Grubba)  if (!read_some_data()) {
eb7d4c1998-04-03Henrik Grubbström (Grubba)  this->sleeping = 0;
b9795b1998-04-03Henrik Grubbström (Grubba)  input_finish();
dc16b41998-04-03Henrik Grubbström (Grubba)  } } else { this->sleeping=0; push_callback(offset_input_read_callback); push_int(0); push_callback(offset_input_close_callback); apply(this->firstinput->u.obj, "set_nonblocking", 3); pop_stack(); }
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  } }
3c39d01997-10-05Per Hedbor  while (!this->firstbuffer)
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  {
3c39d01997-10-05Per Hedbor  if (this->firstinput)
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  { #if defined(HAVE_MMAP) && defined(HAVE_MUNMAP)
3c39d01997-10-05Per Hedbor  if (this->firstinput->type==I_MMAP)
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  {
8c2ec71997-10-10Henrik Grubbström (Grubba)  char *src; struct pike_string *tmp;
3c39d01997-10-05Per Hedbor  if (pos >= this->firstinput->len + this->pos) /* end of mmap */
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  {
8c2ec71997-10-10Henrik Grubbström (Grubba)  this->pos += this->firstinput->len;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  input_finish(); continue; }
8c2ec71997-10-10Henrik Grubbström (Grubba)  len = this->firstinput->len + this->pos - pos;
3c39d01997-10-05Per Hedbor  if (len > READ_BUFFER_SIZE) len=READ_BUFFER_SIZE; tmp = begin_shared_string( len );
8c2ec71997-10-10Henrik Grubbström (Grubba)  src = this->firstinput->u.mmap + pos - this->pos;
3c39d01997-10-05Per Hedbor /* This thread_allow/deny is at the cost of one extra memory copy */ THREADS_ALLOW();
8c2ec71997-10-10Henrik Grubbström (Grubba)  MEMCPY(tmp->str, src, len);
3c39d01997-10-05Per Hedbor  THREADS_DISALLOW(); return end_shared_string(tmp);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  } else #endif
3c39d01997-10-05Per Hedbor  if (this->firstinput->type!=I_OBJ)
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  {
dc16b41998-04-03Henrik Grubbström (Grubba)  /* FIXME: What about I_BLOCKING_OBJ? */
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  input_finish(); /* shouldn't be anything else ... maybe a finished object */ } } return NULL; /* no data */ }
3c39d01997-10-05Per Hedbor  if (pos==this->pos)
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  {
d6ac731998-04-20Henrik Grubbström (Grubba)  add_ref(this->firstbuffer->s);
3c39d01997-10-05Per Hedbor  return this->firstbuffer->s;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  }
3c39d01997-10-05Per Hedbor  return make_shared_binary_string(this->firstbuffer->s->str+ pos-this->pos, this->firstbuffer->s->len- pos+this->pos);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) } /* * close and free the contents of a struct output * Note that the output struct is not freed or unlinked here, * that is taken care of later. */ static INLINE void output_finish(struct object *obj) {
ce3f4d1999-03-05Wilhelm Köhler  struct output *o, *oi; struct object *obji;
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
1047302000-08-28Fredrik Hübinette (Hubbe)  debug_malloc_touch(obj);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  o=(struct output *)(obj->storage); if (o->obj) {
ce3f4d1999-03-05Wilhelm Köhler  if(obj==THIS->firstoutput){ THIS->firstoutput=o->next; } else for(obji=THIS->firstoutput;obji;obji=oi->next) { oi=(struct output *)(obji->storage); if(oi->next==obj) { oi->next=o->next; } }
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if(o->obj->prog) { #ifdef BLOCKING_CLOSE apply_low(o->obj,o->set_blocking_offset,0); pop_stack(); #endif push_int(0); apply(o->obj,"set_id",1); pop_stack(); apply(o->obj,"close",0); pop_stack(); if(!THISOBJ->prog)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Pipe done callback destructed pipe.\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  destruct(o->obj); } free_object(o->obj); noutputs--; o->obj=NULL; THIS->living_outputs--; finished_p(); /* Moved by per, one line down.. :) */
2304231999-03-05Henrik Grubbström (Grubba)  /* free_object(THISOBJ); */ /* What? /Hubbe */
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  } } /* * Try to write some data to our precious output */ static INLINE void output_try_write_some(struct object *obj) { struct output *out; struct pike_string *s;
d7ae232000-08-10Henrik Grubbström (Grubba)  size_t len; INT_TYPE ret;
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
1047302000-08-28Fredrik Hübinette (Hubbe)  debug_malloc_touch(obj);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  out=(struct output*)(obj->storage); #ifdef INSISTANT_WRITE do { #endif /* Get some data to write */ s=gimme_some_data(out->pos); if (!s) /* out of data */ { /* out of data, goto sleep */ if (!THIS->firstinput || !out->obj->prog) /* end of life */ { output_finish(obj); } else { apply_low(out->obj, out->set_blocking_offset, 0); pop_stack(); /* from apply */ out->mode=O_SLEEP; } return; } len=s->len; push_string(s); apply_low(out->obj,out->write_offset,1); out->mode=O_RUN; ret=-1; if(sp[-1].type == T_INT) ret=sp[-1].u.integer; pop_stack();
a4a1722000-12-05Per Hedbor  if (ret==-1) /* error, byebye */
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  { output_finish(obj); return; } out->pos+=ret;
a4dbbb1997-08-29Marcus Comstedt  THIS->sent+=ret;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  #ifdef INSISTANT_WRITE } while(ret == len); #endif } /********** methods *********************************************************/ /* Add an input to this pipe */ static void pipe_input(INT32 args) { struct input *i; int fd=-1; /* Per, one less warning to worry about... */ struct object *obj; if (args<1 || sp[-args].type != T_OBJECT)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Bad/missing argument 1 to pipe->input().\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  obj=sp[-args].u.object; if(!obj || !obj->prog)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("pipe->input() on destructed object.\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  push_int(0); apply(sp[-args-1].u.object,"set_id", 1); pop_stack(); i=new_input(); #if defined(HAVE_MMAP) && defined(HAVE_MUNMAP) /* We do not handle mmaps if we have a buffer */ if(THIS->fd == -1) {
4d4cc22001-09-24Henrik Grubbström (Grubba)  char *m; struct stat s;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  apply(obj, "query_fd", 0); if(sp[-1].type == T_INT) fd=sp[-1].u.integer; pop_stack(); if (fd != -1 && fstat(fd,&s)==0) {
f7c4332003-10-07Martin Stjernholm  off_t filep=fd_lseek(fd, 0L, SEEK_CUR); /* keep the file pointer */ size_t len = s.st_size - filep;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if(S_ISREG(s.st_mode) /* regular file */
f7c4332003-10-07Martin Stjernholm  && ((m=(char *)mmap(0, len, PROT_READ,
f8aaf22003-01-04Henrik Grubbström (Grubba)  MAP_FILE|MAP_SHARED,fd,filep))+1))
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  {
f7c4332003-10-07Martin Stjernholm  mmapped += len;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  i->type=I_MMAP;
f7c4332003-10-07Martin Stjernholm  i->len = len;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  i->u.mmap=m;
1e50b81999-07-29Henrik Grubbström (Grubba) #if defined(HAVE_MADVISE) && defined(MADV_SEQUENTIAL)
3c39d01997-10-05Per Hedbor  /* Mark the pages as sequential read only access... */
f7c4332003-10-07Martin Stjernholm  madvise(m, len, MADV_SEQUENTIAL);
3c39d01997-10-05Per Hedbor #endif
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  pop_n_elems(args); push_int(0); return; } } } #endif i->u.obj=obj; nobjects++; i->type=I_OBJ;
d6ac731998-04-20Henrik Grubbström (Grubba)  add_ref(i->u.obj);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  i->set_nonblocking_offset=find_identifier("set_nonblocking",i->u.obj->prog); i->set_blocking_offset=find_identifier("set_blocking",i->u.obj->prog); if (i->set_nonblocking_offset<0 || i->set_blocking_offset<0) {
dc16b41998-04-03Henrik Grubbström (Grubba)  if (find_identifier("read", i->u.obj->prog) < 0) { /* Not even a read function */ free_object(i->u.obj); i->u.obj=NULL; i->type=I_NONE; nobjects--;
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("illegal file object%s%s\n",
dc16b41998-04-03Henrik Grubbström (Grubba)  ((i->set_nonblocking_offset<0)?"; no set_nonblocking":""), ((i->set_blocking_offset<0)?"; no set_blocking":"")); } else { /* Try blocking mode */ i->type = I_BLOCKING_OBJ;
7dd0c61998-04-03Henrik Grubbström (Grubba)  if (i==THIS->firstinput) {
0273ae1998-07-22Henrik Grubbström (Grubba)  /* * FIXME: What if read_som_data() returns 0? */
7dd0c61998-04-03Henrik Grubbström (Grubba)  read_some_data(); }
dc16b41998-04-03Henrik Grubbström (Grubba)  return; }
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  } if (i==THIS->firstinput) { push_callback(offset_input_read_callback); push_int(0); push_callback(offset_input_close_callback); apply_low(i->u.obj,i->set_nonblocking_offset,3); pop_stack(); } else { /* DOESN'T WORK!!! */ push_int(0); push_int(0); push_callback(offset_input_close_callback); apply_low(i->u.obj,i->set_nonblocking_offset,3); pop_stack(); } pop_n_elems(args); push_int(0); } static void pipe_write(INT32 args) { struct input *i; if (args<1 || sp[-args].type!=T_STRING)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("illegal argument to pipe->write()\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if (!THIS->firstinput) { append_buffer(sp[-args].u.string); pop_n_elems(args); push_int(0); return; } i=new_input(); i->type=I_STRING; nstrings++;
d6ac731998-04-20Henrik Grubbström (Grubba)  add_ref(i->u.str=sp[-args].u.string);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  pop_n_elems(args-1); } void f_mark_fd(INT32 args); static void pipe_output(INT32 args) { struct object *obj; struct output *o; int fd; struct stat s; struct buffer *b; if (args<1 || sp[-args].type != T_OBJECT || !sp[-args].u.object || !sp[-args].u.object->prog)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Bad/missing argument 1 to pipe->output().\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
ce3f4d1999-03-05Wilhelm Köhler  if (args==2 && sp[1-args].type != T_INT)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Bad argument 2 to pipe->output().\n");
ce3f4d1999-03-05Wilhelm Köhler 
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if (THIS->fd==-1) /* no buffer */ { /* test if usable as buffer */ apply(sp[-args].u.object,"query_fd",0); if ((sp[-1].type==T_INT) && (fd=sp[-1].u.integer)>=0 && (fstat(fd,&s)==0) && S_ISREG(s.st_mode)
8c461c2000-07-02Henrik Grubbström (Grubba)  && (THIS->fd=fd_dup(fd))!=-1 )
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  {
41362a1997-03-20Wilhelm Köhler  /* keep the file pointer of the duped fd */
8c461c2000-07-02Henrik Grubbström (Grubba)  THIS->pos=fd_lseek(fd, 0L, SEEK_CUR);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  THIS->living_outputs++; while (THIS->firstbuffer) { b=THIS->firstbuffer; THIS->firstbuffer=b->next;
8c461c2000-07-02Henrik Grubbström (Grubba)  fd_lseek(THIS->fd, THIS->pos, SEEK_SET); fd_write(THIS->fd,b->s->str,b->s->len);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  sbuffers-=b->s->len; nbuffers--; free_string(b->s); free((char *)b); } THIS->lastbuffer=NULL;
41362a1997-03-20Wilhelm Köhler  /* keep the file pointer of the duped fd THIS->pos=0; */
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  push_int(0); apply(sp[-args-2].u.object,"set_id", 1); pop_n_elems(args+2); /* ... and from apply x 2 */ return; } pop_stack(); /* from apply */ } THIS->living_outputs++;
2304231999-03-05Henrik Grubbström (Grubba)  /* add_ref(THISOBJ); */ /* Weird */
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  /* Allocate a new struct output */
e709751997-03-12Fredrik Hübinette (Hubbe)  obj=clone_object(output_program,0);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  o=(struct output *)(obj->storage); o->next=THIS->firstoutput; THIS->firstoutput=obj; noutputs++; o->obj=NULL;
d6ac731998-04-20Henrik Grubbström (Grubba)  add_ref(o->obj=sp[-args].u.object);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  o->write_offset=find_identifier("write",o->obj->prog); o->set_nonblocking_offset=find_identifier("set_nonblocking",o->obj->prog); o->set_blocking_offset=find_identifier("set_blocking",o->obj->prog); if (o->write_offset<0 || o->set_nonblocking_offset<0 || o->set_blocking_offset<0) { free_object(o->obj);
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("illegal file object%s%s%s\n",
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  ((o->write_offset<0)?"; no write":""), ((o->set_nonblocking_offset<0)?"; no set_nonblocking":""), ((o->set_blocking_offset<0)?"; no set_blocking":"")); } o->mode=O_RUN;
41362a1997-03-20Wilhelm Köhler  /* keep the file pointer of the duped fd o->pos=0; */
ce3f4d1999-03-05Wilhelm Köhler  /* allow start position as 2nd argument for additional outputs o->pos=THIS->pos; */ if(args>=2) o->pos=sp[1-args].u.integer; else o->pos=THIS->pos;
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
1047302000-08-28Fredrik Hübinette (Hubbe)  push_object(obj); /* Ok, David, this is probably correct, but I dare you to explain why :) */
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  apply(o->obj,"set_id",1); pop_stack(); push_int(0); push_callback(offset_output_write_callback); push_callback(offset_output_close_callback); apply_low(o->obj,o->set_nonblocking_offset,3); pop_stack(); pop_n_elems(args-1); } static void pipe_set_done_callback(INT32 args) { if (args==0) { free_svalue(&THIS->done_callback); THIS->done_callback.type=T_INT; return; } if (args<1 || (sp[-args].type!=T_FUNCTION && sp[-args].type!=T_ARRAY))
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Illegal argument to set_done_callback()\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if (args>1) { free_svalue(&THIS->id); assign_svalue_no_free(&(THIS->id),sp-args+1); } free_svalue(&THIS->done_callback); assign_svalue_no_free(&(THIS->done_callback),sp-args); pop_n_elems(args-1); } static void pipe_set_output_closed_callback(INT32 args) { if (args==0) {
ce3f4d1999-03-05Wilhelm Köhler  free_svalue(&THIS->output_closed_callback);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  THIS->output_closed_callback.type=T_INT; return; } if (args<1 || (sp[-args].type!=T_FUNCTION && sp[-args].type!=T_ARRAY))
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Illegal argument to set_output_closed_callback()\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if (args>1) { free_svalue(&THIS->id); assign_svalue_no_free(&(THIS->id),sp-args+1); } free_svalue(&THIS->output_closed_callback); assign_svalue_no_free(&(THIS->output_closed_callback),sp-args); pop_n_elems(args-1); } static void pipe_finish(INT32 args) { pop_n_elems(args); push_int(0); pipe_done(); } static void pipe_start(INT32 args) /* force start */ { low_start(); if(args) pop_n_elems(args-1); }
a4dbbb1997-08-29Marcus Comstedt static void f_bytes_sent(INT32 args) { pop_n_elems(args); push_int(THIS->sent); }
ab6aec1997-02-11Fredrik Hübinette (Hubbe) /********** callbacks *******************************************************/ static void pipe_write_output_callback(INT32 args) { if (args<1 || sp[-args].type!=T_OBJECT)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Illegal argument to pipe->write_output_callback\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if(!sp[-args].u.object->prog) return; if(sp[-args].u.object->prog != output_program)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Illegal argument to pipe->write_output_callback\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
1047302000-08-28Fredrik Hübinette (Hubbe)  debug_malloc_touch(sp[-args].u.object);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  output_try_write_some(sp[-args].u.object); pop_n_elems(args-1); } static void pipe_close_output_callback(INT32 args) { struct output *o; if (args<1 || sp[-args].type!=T_OBJECT) if(!sp[-args].u.object->prog) return; if(sp[-args].u.object->prog != output_program)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Illegal argument to pipe->close_output_callback\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  o=(struct output *)(sp[-args].u.object->storage); if (THIS->output_closed_callback.type!=T_INT) { assign_svalue_no_free(sp++,&THIS->id); push_object(o->obj); apply_svalue(&(THIS->output_closed_callback),2); pop_stack(); } output_finish(sp[-args].u.object); pop_n_elems(args-1); } static void pipe_read_input_callback(INT32 args) { struct input *i; struct pike_string *s; if (args<2 || sp[1-args].type!=T_STRING)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Illegal argument to pipe->read_input_callback\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  i=THIS->firstinput; if (!i)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Pipe read callback without any inputs left.\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  s=sp[1-args].u.string; if(append_buffer(s)) { /* THIS DOES NOT WORK */ push_int(0); push_int(0); push_callback(offset_input_close_callback); apply_low(i->u.obj,i->set_nonblocking_offset,3); pop_stack(); THIS->sleeping=1; } low_start(); pop_n_elems(args-1); } static void pipe_close_input_callback(INT32 args) { struct input *i; i=THIS->firstinput; if(!i)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Input close callback without inputs!\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if(i->type != I_OBJ)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Premature close callback on pipe!.\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if (i->u.obj->prog) { #ifdef BLOCKING_CLOSE apply_low(i->u.obj,i->set_blocking_offset,0); pop_stack(); #endif apply(i->u.obj,"close",0); pop_stack(); } nobjects--; free_object(i->u.obj); i->type=I_NONE; input_finish(); if(args) pop_n_elems(args-1); } static void pipe_version(INT32 args) { pop_n_elems(args);
90e0f72003-12-12Martin Nilsson  push_text("PIPE ver 2.0");
ab6aec1997-02-11Fredrik Hübinette (Hubbe) } /********** init/exit *******************************************************/ void close_and_free_everything(struct object *thisobj,struct pipe *p) { struct buffer *b; struct input *i; struct output *o; struct object *obj;
1047302000-08-28Fredrik Hübinette (Hubbe)  debug_malloc_touch(thisobj); debug_malloc_touch(p);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
ce3f4d1999-03-05Wilhelm Köhler  if(p->done){ return; }
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  p->done=1; if (thisobj)
d6ac731998-04-20Henrik Grubbström (Grubba)  add_ref(thisobj); /* don't kill object during this */
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  while (p->firstbuffer) { b=p->firstbuffer; p->firstbuffer=b->next; sbuffers-=b->s->len; nbuffers--; free_string(b->s); b->next=NULL; free((char *)b); /* Hubbe */ } p->lastbuffer=NULL; while (p->firstinput) { i=p->firstinput; p->firstinput=i->next; free_input(i); } p->lastinput=NULL; while (p->firstoutput) { obj=p->firstoutput; o=(struct output *)(obj->storage); p->firstoutput=o->next; output_finish(obj); free_object(obj); } if (p->fd!=-1) {
8c461c2000-07-02Henrik Grubbström (Grubba)  fd_close(p->fd);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  p->fd=-1; } p->living_outputs=0; if (thisobj) free_object(thisobj); free_svalue(& p->done_callback); free_svalue(& p->output_closed_callback); free_svalue(& p->id); p->done_callback.type=T_INT; p->output_closed_callback.type=T_INT; p->id.type=T_INT;
ce3f4d1999-03-05Wilhelm Köhler  /* p->done=0; */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) } static void init_pipe_struct(struct object *o) {
1047302000-08-28Fredrik Hübinette (Hubbe)  debug_malloc_touch(o);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  THIS->firstbuffer=THIS->lastbuffer=NULL; THIS->firstinput=THIS->lastinput=NULL; THIS->firstoutput=NULL; THIS->bytes_in_buffer=0; THIS->pos=0; THIS->sleeping=0; THIS->done=0; THIS->fd=-1; THIS->done_callback.type=T_INT; THIS->output_closed_callback.type=T_INT; THIS->id.type=T_INT; THIS->id.u.integer=0; THIS->living_outputs=0;
a4dbbb1997-08-29Marcus Comstedt  THIS->sent=0;
ab6aec1997-02-11Fredrik Hübinette (Hubbe) } static void exit_pipe_struct(struct object *o) { close_and_free_everything(NULL,THIS); } static void exit_output_struct(struct object *obj) { struct output *o;
1047302000-08-28Fredrik Hübinette (Hubbe)  debug_malloc_touch(obj);
a315182000-07-07Henrik Grubbström (Grubba)  o=(struct output *)(Pike_fp->current_storage);
1047302000-08-28Fredrik Hübinette (Hubbe) 
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if (o->obj) { if(o->obj->prog) { #ifdef BLOCKING_CLOSE apply_low(o->obj,o->set_blocking_offset,0); pop_stack(); #endif push_int(0); apply(o->obj,"set_id",1); pop_stack(); apply(o->obj,"close",0); pop_stack(); if(!THISOBJ->prog)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Pipe done callback destructed pipe.\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  } free_object(o->obj); noutputs--; o->obj=0;
ce3f4d1999-03-05Wilhelm Köhler  o->fd=-1;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  } } static void init_output_struct(struct object *ob) { struct output *o;
1047302000-08-28Fredrik Hübinette (Hubbe)  debug_malloc_touch(ob);
a315182000-07-07Henrik Grubbström (Grubba)  o=(struct output *)(Pike_fp->current_storage);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  o->obj=0; } /********** Pike init *******************************************************/ void port_setup_program(void); void f__pipe_debug(INT32 args) { pop_n_elems(args);
d098b22000-08-09Henrik Grubbström (Grubba)  push_int(DO_NOT_WARN(noutputs)); push_int(DO_NOT_WARN(ninputs)); push_int(DO_NOT_WARN(nstrings)); push_int(DO_NOT_WARN(nobjects)); push_int(DO_NOT_WARN(mmapped)); push_int(DO_NOT_WARN(nbuffers)); push_int(DO_NOT_WARN(sbuffers));
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  f_aggregate(7); }
51ef5c2002-10-21Marcus Comstedt PIKE_MODULE_INIT
ab6aec1997-02-11Fredrik Hübinette (Hubbe) { start_new_program();
90e9781999-01-31Fredrik Hübinette (Hubbe)  ADD_STORAGE(struct pipe);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(object:void) */ ADD_FUNCTION("input",pipe_input,tFunc(tObj,tVoid),0);
ce3f4d1999-03-05Wilhelm Köhler  /* function(object,void|int:void) */
2304231999-03-05Henrik Grubbström (Grubba)  ADD_FUNCTION("output",pipe_output,tFunc(tObj tOr(tVoid,tInt),tVoid),0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(string:void) */ ADD_FUNCTION("write",pipe_write,tFunc(tStr,tVoid),0); /* function(:void) */
07228a1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("start",pipe_start,tFunc(tNone,tVoid),0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(:void) */
07228a1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("finish",pipe_finish,tFunc(tNone,tVoid),0);
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(void|function(mixed,object:mixed),void|mixed:void) */ ADD_FUNCTION("set_output_closed_callback",pipe_set_output_closed_callback,tFunc(tOr(tVoid,tFunc(tMix tObj,tMix)) tOr(tVoid,tMix),tVoid),0); /* function(void|function(mixed:mixed),void|mixed:void) */ ADD_FUNCTION("set_done_callback",pipe_set_done_callback,tFunc(tOr(tVoid,tFunc(tMix,tMix)) tOr(tVoid,tMix),tVoid),0);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(int:void) */ ADD_FUNCTION("_output_close_callback",pipe_close_output_callback,tFunc(tInt,tVoid),0); /* function(int:void) */ ADD_FUNCTION("_input_close_callback",pipe_close_input_callback,tFunc(tInt,tVoid),0); /* function(int:void) */ ADD_FUNCTION("_output_write_callback",pipe_write_output_callback,tFunc(tInt,tVoid),0); /* function(int,string:void) */ ADD_FUNCTION("_input_read_callback",pipe_read_input_callback,tFunc(tInt tStr,tVoid),0); /* function(:string) */
07228a1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("version",pipe_version,tFunc(tNone,tStr),0);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
45ee5d1999-02-10Fredrik Hübinette (Hubbe)  /* function(:int) */
07228a1999-06-19Fredrik Hübinette (Hubbe)  ADD_FUNCTION("bytes_sent",f_bytes_sent,tFunc(tNone,tInt),0);
a4dbbb1997-08-29Marcus Comstedt 
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  set_init_callback(init_pipe_struct); set_exit_callback(exit_pipe_struct); pipe_program=end_program(); add_program_constant("pipe",pipe_program, 0); offset_output_close_callback=find_identifier("_output_close_callback", pipe_program); offset_input_close_callback=find_identifier("_input_close_callback", pipe_program); offset_output_write_callback=find_identifier("_output_write_callback", pipe_program); offset_input_read_callback=find_identifier("_input_read_callback", pipe_program); start_new_program();
90e9781999-01-31Fredrik Hübinette (Hubbe)  ADD_STORAGE(struct output);
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  set_init_callback(init_output_struct); set_exit_callback(exit_output_struct); output_program=end_program(); add_program_constant("__output",output_program, 0);
a63be92003-04-02Martin Nilsson  /* function(:array) */ ADD_FUNCTION("_pipe_debug", f__pipe_debug,tFunc(tNone,tArray), 0);
ab6aec1997-02-11Fredrik Hübinette (Hubbe) }
51ef5c2002-10-21Marcus Comstedt PIKE_MODULE_EXIT
ab6aec1997-02-11Fredrik Hübinette (Hubbe) { if(pipe_program) free_program(pipe_program); pipe_program=0; if(output_program) free_program(output_program); output_program=0; }