예제 #1
0
/* free output object */
static INLINE  void free_output(output *outp) {
  noutputs--;
  push_int(0);    push_int(0);    push_int(0);
  apply_low(outp->file, outp->set_nb_off, 3);
  apply_low(outp->file, outp->set_b_off, 0);
  pop_n_elems(2);
  free_object(outp->file);
  free(outp);
}
예제 #2
0
파일: pipe.c 프로젝트: ajinkya007/pike-1
/*
 * 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;
  size_t len;
  INT_TYPE ret;
  
   debug_malloc_touch(obj);

  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();

    if (ret==-1)		/* error, byebye */
    {
      output_finish(obj);
      return;
    }
    out->pos+=ret;
    THIS->sent+=ret;

#ifdef INSISTANT_WRITE
  } while(ret == len);
#endif
}
예제 #3
0
/* Free an input */
static INLINE void free_input(input *inp) {
  ninputs--;
  switch(inp->type) {
  case NBIO_STR:
    DERR(fprintf(stderr, "Freeing string input 0x%x\n", (unsigned int)inp));
    free_string(inp->u.data);
    nstrings--;
    break;
#ifdef USE_MMAP
  case NBIO_MMAP:
    DERR(fprintf(stderr, "Freeing mmap input 0x%x\n", (unsigned int)inp));
    if(inp->u.mmap_storage->data != MAP_FAILED) {
      munmap(inp->u.mmap_storage->data, inp->u.mmap_storage->m_len);
      mmapped -= inp->u.mmap_storage->m_len;
    }
    push_int(0);    push_int(0);    push_int(0);
    apply_low(inp->u.mmap_storage->file, inp->set_nb_off, 3);
    apply_low(inp->u.mmap_storage->file, inp->set_b_off, 0);
    pop_n_elems(2);
    free_object(inp->u.mmap_storage->file);
    free(inp->u.mmap_storage);
    break;
#endif
  case NBIO_OBJ:
    push_int(0);    push_int(0);    push_int(0);
    apply_low(inp->u.file, inp->set_nb_off, 3);
    apply_low(inp->u.file, inp->set_b_off, 0);
    pop_n_elems(2);
    /* FALL THROUGH */
    
  case NBIO_BLOCK_OBJ:
    DERR(fprintf(stderr, "Freeing obj input 0x%x\n", (unsigned int)inp));
    free_object(inp->u.file);
    nobjects--;
    break;
    
  }
  if(THIS->last_input == inp)
    THIS->last_input = NULL;
  THIS->inputs = inp->next;
  if(!THIS->finished && THIS->inputs && THIS->inputs->type == NBIO_OBJ) {
    /* Aha! Set read callback here */
    DERR(fprintf(stderr, "Setting read/close callbacks for input 0x%x\n", (unsigned int)THIS->inputs));
    push_callback(input_read_cb_off);
    push_int(0);
    push_callback(input_close_cb_off);
    apply_low(THIS->inputs->u.file, THIS->inputs->set_nb_off, 3);
    THIS->inputs->mode = READING;    
  }
  free(inp);
}
예제 #4
0
파일: pipe.c 프로젝트: ajinkya007/pike-1
static void pipe_close_input_callback(INT32 args)
{
   struct input *i;
   i=THIS->firstinput;

   if(!i)
     Pike_error("Input close callback without inputs!\n");

   if(i->type != I_OBJ)
     Pike_error("Premature close callback on pipe!.\n");

   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);
}
예제 #5
0
파일: pipe.c 프로젝트: ajinkya007/pike-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)
    Pike_error("Illegal argument to pipe->read_input_callback\n");
   
  i=THIS->firstinput;

  if (!i)
    Pike_error("Pipe read callback without any inputs left.\n");

  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);
}
예제 #6
0
파일: pipe.c 프로젝트: ajinkya007/pike-1
/* Wake up the sleepers */
static void low_start(void)
{
  struct object *obj, *next;
  struct output *o;


  add_ref(THISOBJ);		/* dont kill yourself now */
  for(obj=THIS->firstoutput;obj;obj=next)
  {
    /* add_ref(obj); */		/* Hang on PLEASE!! /hubbe */
    o=(struct output *)(obj->storage);
    next=o->next;
    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);
	/* output_try_write_some(obj); */
	/* o->mode=O_RUN; */		/* Hubbe */
      }
    }
    /* next=o->next; */
    /* free_object(obj); */
  }

  free_object(THISOBJ);
}
예제 #7
0
파일: pipe.c 프로젝트: ajinkya007/pike-1
static void exit_output_struct(struct object *obj)
{
  struct output *o;
  
   debug_malloc_touch(obj);
  o=(struct output *)(Pike_fp->current_storage);

  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)
	Pike_error("Pipe done callback destructed pipe.\n");
    }
    free_object(o->obj);
    noutputs--;
    o->obj=0;
    o->fd=-1;
  }
}
예제 #8
0
static INLINE void set_outp_write_cb(output *outp) {
  /* Need to set_nonblocking again to trigger the write cb again.
   * FIXME: only call when there is more to write...
   */
  if(outp != NULL) {
    DERR(fprintf(stderr, "Setting output write callback.\n"));
    push_int(0);
    push_callback(output_write_cb_off);
    push_int(0);
    apply_low(outp->file, outp->set_nb_off, 3);
    pop_stack();
  }
}  
예제 #9
0
파일: pipe.c 프로젝트: ajinkya007/pike-1
/*
 * 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)
{
  struct output *o, *oi;
  struct object *obji;

  debug_malloc_touch(obj);

  o=(struct output *)(obj->storage);

  if (o->obj)
  {
    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;
      }
    }
    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)
	Pike_error("Pipe done callback destructed pipe.\n");
      destruct(o->obj);
    }
    free_object(o->obj);
    noutputs--;
    o->obj=NULL;

    THIS->living_outputs--;

    finished_p(); /* Moved by per, one line down.. :) */

    /* free_object(THISOBJ); */		/* What? /Hubbe */
  }
}
예제 #10
0
/* Our nb input read callback */
static void f__input_read_cb(INT32 args)
{
  int avail_size = 0, len;
  struct pike_string *str;
  input *inp = THIS->inputs;
  if(inp == NULL) {
    Pike_error("Input read callback without inputs.");
  }    
  if(args != 2)
    Pike_error("Invalid number of arguments to read callback.");
  if(ARG(2).type != T_STRING) {
    SIMPLE_BAD_ARG_ERROR("_Caudium.nbio()->_input_read_cb", 2, "string");
  }
  str = ARG(2).u.string;
  len = str->len << str->size_shift;
  inp->pos += len;
  if(inp->len != -1 && inp->pos >= inp->len) {
    len -= inp->pos - inp->len; /* Don't "read" too much */
    DERR(fprintf(stderr, "Read all wanted input data.\n"));
    free_input(inp);
  }
  DERR(fprintf(stderr, "Input read callback (got %d bytes).\n", len));
  if(THIS->buf_size) {
    avail_size = THIS->buf_size - (THIS->buf_len + THIS->buf_pos);
  } 
  if(avail_size < len) {
    alloc_data_buf(THIS->buf_size + (len - avail_size));
  }
  DERR(fprintf(stderr, "Copying %d bytes to buf starting at 0x%x (pos %d).\n",
	       len, (int)(THIS->buf + THIS->buf_pos + THIS->buf_len), THIS->buf_pos + THIS->buf_len));
  memcpy(THIS->buf + THIS->buf_pos + THIS->buf_len, str->str, len);
  THIS->buf_len += len;
  if((THIS->buf_len + THIS->buf_pos) > READ_BUFFER_SIZE) {
    DERR(fprintf(stderr, "Read buffer full (%d bytes).\n", THIS->buf_size));
    push_int(0);   push_int(0);  push_int(0);
    apply_low(inp->u.file, inp->set_nb_off, 3);
    pop_stack();
    inp->mode = SLEEPING;
  }
  pop_n_elems(args);
  
  if(THIS->outp->mode == IDLE) {
    DERR(fprintf(stderr, "Waking up output.\n"));
    THIS->outp->mode = ACTIVE;
    f__output_write_cb(0);
  } else {
    DERR(fprintf(stderr, "Output is awake.\n"));
  }
}
예제 #11
0
파일: pipe.c 프로젝트: ajinkya007/pike-1
/* Let's guess what this function does....
 *
 */
static INLINE void input_finish(void)
{
  struct input *i;

  while(1)
  {
    /* Get the next input from the queue */
    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;

    case I_BLOCKING_OBJ:
      if (read_some_data())
	return;
      continue;

    case I_MMAP:
      if (THIS->fd==-1) return;
      continue;

    case I_STRING:
      append_buffer(i->u.str);

    case I_NONE: break;
    }
  }
  THIS->sleeping=0;

  low_start();
  finished_p();
}
예제 #12
0
파일: pipe.c 프로젝트: ajinkya007/pike-1
/* Free an input struct and all that it stands for */
static INLINE void free_input(struct input *i)
{
  debug_malloc_touch(i);

  ninputs--;
  switch (i->type)
  {
  case I_OBJ:
  case I_BLOCKING_OBJ:
    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
    Pike_error("I_MMAP input when MMAP is diabled!");
#endif
    break;

  case I_NONE: break;
  }
  free((char *)i);
}
예제 #13
0
static INLINE int do_write(char *buf, int buf_len) {
  int fd, written = 0;
  fd = THIS->outp->fd;
 write_retry:
  if(fd != -1) {
    DERR(fprintf(stderr, "do_write() to real fd\n"));
    THREADS_ALLOW();
    written = fd_write(fd, buf, buf_len);
    THREADS_DISALLOW();  
  } else {
    DERR(fprintf(stderr, "do_write() to fake fd\n"));
    push_string(make_shared_binary_string(buf, buf_len));
    apply_low(THIS->outp->file, THIS->outp->write_off, 1);
    if(Pike_sp[-1].type != T_INT) {
      written = -1;
    } else {
      written = Pike_sp[-1].u.integer;
    }
    pop_stack();
  }

  if(written < 0)
  { 
    DERR(fprintf(stderr, "write returned -1...\n"));
    switch(errno)
    {      
    default:
      DERR(perror("Error while writing"));
      finished();
      return -1; /* -1 == write failed and that's it */
    case EINTR: /* interrupted by signal - try again */
      DERR(fprintf(stderr, "write -> EINTR = retry.\n"));
      goto write_retry;
    case EWOULDBLOCK:
      DERR(fprintf(stderr, "would block.\n"));
      return 0; /* Treat this as if we wrote no data */      
    }
  } else {
    DERR(fprintf(stderr, "Wrote %d bytes of %d\n", written, buf_len));
    THIS->written += written;
  }
  return written;
}
예제 #14
0
파일: dwlib.c 프로젝트: Yuffster/fluffOS
/* Hideous mangling of C code by Taffyd. */ 
void query_multiple_short(svalue_t * arg, const char * type, int no_dollars, int quiet, int dark, int num_arg) { 
    char m[] = "$M$";
    char s[] = "_short";
    char default_function[] = "a_short";
    char separator[] = ", ";
    char andsep[] = " and ";
    int mlen = strlen(m);
    int slen = strlen(s);
    int seplen = strlen( separator );
    int andlen = strlen( andsep );

    array_t *arr = arg->u.arr;
    svalue_t *sv;
    svalue_t *v;
    int size = arr->size;
    int i;
    int len;
    int total_len;
    char *str, *res;
    object_t *ob;
    char *fun; 

    if (!size) {
        str = new_string(0, "f_query_multiple_short");
        str[0] = '\0';
        pop_n_elems(num_arg);
        push_malloced_string(str);
        return; 
    }
    
    /* 
    if (no_dollars && sizeof(args) && objectp(args[0]) && undefinedp(dark) && 
        this_player() && environment(this_player())) {
        dark = this_player()->check_dark(environment(this_player())->query_light());
        if (dark) {
        return "some objects you cannot make out";
        }
    } */ 

    if (no_dollars && arr->item->type == T_OBJECT && !dark && command_giver &&
        command_giver->super) { 
        call_origin = ORIGIN_EFUN;
        if(!apply_low("query_light", command_giver->super, 0))
            push_number(0);
        v = apply("check_dark", command_giver, 1, ORIGIN_EFUN);
        
        if (v && v->type == T_NUMBER && v->u.number) {
            pop_n_elems(num_arg);
            copy_and_push_string("some objects you cannot make out"); 
            return;
        }
    }

    /* If we don't have a type parameter, then use default_function */ 
    /* We need to free this value with FREE_MSTR() */ 

    if ( !type ) { 
        len = strlen( default_function );
        fun = new_string( len, "f_query_multiple_short");
        fun[len] = '\0';
        strncpy( fun, default_function, len );
    }
    else { 
        len = strlen( type ) + slen;
        fun = new_string( len, "f_query_multiple_short");
        fun[len] = '\0';
        strncpy( fun, type, len );
        strncpy( fun + strlen( type ), s, slen);
    }
   
    /* Check to see if there are any non-objects in the array. */ 
    for (i = 0; i < size; i++) {
        if ((arr->item + i)->type != T_OBJECT) {
            break;
        }
    }

    /* The array consists only of objects, and will use the $M$ 
       expansion code. */ 
    if (i == size && !no_dollars) {
        str = new_string(max_string_length, "f_query_multiple_short");
        str[max_string_length]= '\0';
        strncpy(str, m, mlen);
        total_len = mlen;

        for ( i = 0; i < size; i++ ) {
            sv = (arr->item + i);
            push_number(quiet);
            v = apply(fun, sv->u.ob, 1, ORIGIN_EFUN);

            if (!v || v->type != T_STRING) {
                continue;                
            }
            if(total_len + SVALUE_STRLEN(v) > max_string_length - mlen)
                continue;
            strncpy(str + total_len, v->u.string, (len = SVALUE_STRLEN(v)));
            total_len += len;
        }

        strncpy(str + total_len, m, mlen);
        total_len += mlen;

        res = new_string( total_len, "f_query_multiple_short" );
        res[ total_len ] = '\0';
        memcpy(res, str, total_len);

        /* Clean up our temporary buffer. */ 

        FREE_MSTR(str);
        FREE_MSTR(fun);

        pop_n_elems(num_arg);
        push_malloced_string(res);
        return;
    }

    /* This is a mixed array, so we don't use $M$ format.  Instead, we 
       do as much $a_short$ conversion as we can etc.  */ 

    str = new_string(max_string_length, "f_query_multiple_short");
    str[max_string_length]= '\0';
    total_len = 0;

    for ( i = 0; i < size; i++ ) {
        sv = (arr->item + i);
    
        switch(sv->type) {
            case T_STRING:
                len = SVALUE_STRLEN(sv);
                if(total_len + len < max_string_length){
                    strncpy(str + total_len, sv->u.string, len);
                    total_len += len;
                }
                break;
            case T_OBJECT:
                push_number(quiet);
                v = apply(fun, sv->u.ob, 1, ORIGIN_EFUN);

                if (!v || v->type != T_STRING) {
                    continue;                
                }

                if(total_len + SVALUE_STRLEN(v) < max_string_length){
                    strncpy(str + total_len, v->u.string, 
                            (len = SVALUE_STRLEN(v)));
                    total_len += len;
                }

                break;
            case T_ARRAY:
              /* Does anyone use this? */ 
              /* args[ i ] = "$"+ type +"_short:"+ file_name( args[ i ][ 1 ] ) +"$"; */ 
            default:    
                /* Get the next element. */ 
                continue;            
                break;
        }
        
        if ( len && size > 1 ) {
            if ( i < size - 2 ) {
                if(total_len+seplen < max_string_length){
                    strncpy( str + total_len, separator, seplen );
                    total_len += seplen;
                }
            }
            else { 
                if ( i < size - 1 ) {    
                    if(total_len+andlen < max_string_length){
                        strncpy( str + total_len, andsep, andlen );
                        total_len += andlen;
                    }
                }
            }
        }
    }

    FREE_MSTR(fun);

    res = new_string(total_len, "f_query_multiple_short");
    res[total_len] = '\0';
    memcpy(res, str, total_len);

    FREE_MSTR(str);

    /* Ok, now that we have cleaned up here we have to decide what to do
       with it. If nodollars is 0, then we need to pass it to an object
       for conversion. */ 

    if (no_dollars) { 
        if (command_giver) { 
            /* We need to call on this_player(). */ 
            push_malloced_string(res);
            v = apply("convert_message", command_giver, 1, ORIGIN_EFUN);
            
            if (v && v->type == T_STRING) { 
                pop_n_elems(num_arg);
                share_and_push_string(v->u.string);
            }
            else { 
                pop_n_elems(num_arg);
                push_undefined();
            }
            
        }
        else {
            /* We need to find /global/player. */ 
            /* Does this work? Seems not to. */ 
            ob = find_object("/global/player");
            
            if (ob) {
                push_malloced_string(res);
                v = apply("convert_message", ob, 1, ORIGIN_EFUN);
                
                /* Return the result! */ 
                if (v && v->type == T_STRING) { 
                    pop_n_elems(num_arg);
                    share_and_push_string(v->u.string);
                }
                else { 
                    pop_n_elems(num_arg);
                    push_undefined();
                }
            }
            else { 
                pop_n_elems(num_arg);
                push_undefined();
            }
        }

    }
    else { 
        pop_n_elems(num_arg);
        push_malloced_string(res);
    }
} /* query_multiple_short() */
예제 #15
0
파일: pipe.c 프로젝트: ajinkya007/pike-1
/*! @decl void output(object obj, int|void start_pos)
 *!
 *!   Add an output file object.
 */
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)
    Pike_error("Bad/missing argument 1 to pipe->output().\n");

  if (args==2 &&
      sp[1-args].type != T_INT)
    Pike_error("Bad argument 2 to pipe->output().\n");
       
  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)
	&& (THIS->fd=fd_dup(fd))!=-1 )
    {
      /* keep the file pointer of the duped fd */
      THIS->pos=fd_lseek(fd, 0L, SEEK_CUR);

      THIS->living_outputs++;

      while (THIS->firstbuffer)
      {
	b=THIS->firstbuffer;
	THIS->firstbuffer=b->next;
	fd_lseek(THIS->fd, THIS->pos, SEEK_SET);
	fd_write(THIS->fd,b->s->str,b->s->len);
	sbuffers-=b->s->len;
	nbuffers--;
	free_string(b->s);
	free((char *)b);
      }
      THIS->lastbuffer=NULL;

      /* keep the file pointer of the duped fd
	 THIS->pos=0; */
      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++;
  /* add_ref(THISOBJ); */	/* Weird */

  /* Allocate a new struct output */
  obj=clone_object(output_program,0);
  o=(struct output *)(obj->storage);
  o->next=THIS->firstoutput;
  THIS->firstoutput=obj;
  noutputs++;
  o->obj=NULL;

  add_ref(o->obj=sp[-args].u.object);

  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);
    Pike_error("illegal file object%s%s%s\n",
	  ((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;
  /* keep the file pointer of the duped fd
     o->pos=0; */
  /* 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;

  push_object(obj); /* Ok, David, this is probably correct, but I dare you to explain why :) */
  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);
}
예제 #16
0
파일: pipe.c 프로젝트: ajinkya007/pike-1
/*! @decl void input(object obj)
 *!
 *! Add an input file 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)
     Pike_error("Bad/missing argument 1 to pipe->input().\n");

   obj=sp[-args].u.object;
   if(!obj || !obj->prog)
     Pike_error("pipe->input() on destructed object.\n");

   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)
   {
     char *m;
     struct stat s;

     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)
     {
       off_t filep=fd_lseek(fd, 0L, SEEK_CUR); /* keep the file pointer */
       size_t len = s.st_size - filep;
       if(S_ISREG(s.st_mode)	/* regular file */
	  && ((m=(char *)mmap(0, len, PROT_READ,
			      MAP_FILE|MAP_SHARED,fd,filep))+1))
       {
	 mmapped += len;

	 i->type=I_MMAP;
	 i->len = len;
	 i->u.mmap=m;
#if defined(HAVE_MADVISE) && defined(MADV_SEQUENTIAL)
	 /* Mark the pages as sequential read only access... */
	 madvise(m, len, MADV_SEQUENTIAL);
#endif
	 pop_n_elems(args);
	 push_int(0);
	 return;
       }
     }
   }
#endif

   i->u.obj=obj;
   nobjects++;
   i->type=I_OBJ;
   add_ref(i->u.obj);
   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) 
   {
      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--;
	 Pike_error("illegal file object%s%s\n",
	       ((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;
	 if (i==THIS->firstinput) {
	   /*
	    * FIXME: What if read_som_data() returns 0?
	    */
	   read_some_data();
	 }
	 return;
      }
   }
  
   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);
}
예제 #17
0
/* Allocate new input object and add it to our list */
static INLINE void new_input(struct svalue inval, NBIO_INT_T len, int first) {
  struct stat s;
  input *inp;

  inp = malloc(sizeof(input));
  if(inp == NULL) {
    Pike_error("Out of memory!\n");
    return;
  }

  inp->pos  = 0;
  inp->mode = SLEEPING;
  inp->set_nb_off = -1;
  inp->set_b_off  = -1;
  DERR(fprintf(stderr, "Allocated new input at 0x%x\n", (unsigned int)inp));

  if(inval.type == T_STRING) {
    inp->type   = NBIO_STR;
    add_ref(inp->u.data = inval.u.string);
    inp->len = len ? len : inval.u.string->len << inval.u.string->size_shift;
    nstrings++;
    DERR(fprintf(stderr, "string input added: %ld bytes\n", (long)inp->len));
  } else if(inval.type == T_OBJECT) {
    inp->fd     = fd_from_object(inval.u.object);
    inp->len    = len;
    if(inp->fd == -1) {
      /* Fake file object */
      inp->u.file = inval.u.object;
      inp->set_nb_off = find_identifier("set_nonblocking",inp->u.file->prog);
      inp->set_b_off  = find_identifier("set_blocking", inp->u.file->prog);
	
      if(inp->set_nb_off < 0 || inp->set_b_off < 0)
      {
	inp->type   = NBIO_BLOCK_OBJ; /* No set_nonblocking/set_blocking funcs */
	inp->set_nb_off = inp->set_b_off = 0;
	DERR(fprintf(stderr, "New fake blocking input\n"));
      } else {
	inp->type   = NBIO_OBJ; /* Fake nonblocking object */
	DERR(fprintf(stderr, "New fake non-blocking input\n"));
      }
      DERR(fprintf(stderr, "input object not a real FD\n"));
      if ((inp->read_off = find_identifier("read", inp->u.file->prog)) < 0) {
	free(inp);
	Pike_error("_Caudium.nbio()->input: Illegal file object, "
		   "missing read()\n");
	return;
      }
      add_ref(inp->u.file);
      nobjects++;
    } else {
      inp->type   = NBIO_OBJ;
      inp->set_nb_off = find_identifier("set_nonblocking", inval.u.object->prog);
      inp->set_b_off  = find_identifier("set_blocking", inval.u.object->prog);
#ifdef USE_MMAP
      if (fstat(inp->fd, &s) == 0 && S_ISREG(s.st_mode)) 
      {
	char *mtmp;
	unsigned NBIO_INT_T filep = lseek(inp->fd, 0L, SEEK_CUR);
	int alloc_len = MIN(s.st_size - filep, MAX_MMAP_SIZE);
	mtmp = (char *)mmap(0, alloc_len, PROT_READ, MAP_FILE | MAP_SHARED,
			    inp->fd, filep);
	if(mtmp != MAP_FAILED)
	{
	  if( (inp->u.mmap_storage = malloc(sizeof(mmap_data))) == NULL) {
	    Pike_error("Failed to allocate mmap structure. Out of memory?\n");
	  }
	  inp->type   = NBIO_MMAP;
	  inp->len    = s.st_size;
	  inp->pos    = filep;

	  inp->u.mmap_storage->data    = mtmp;
	  inp->u.mmap_storage->m_start = filep;
	  inp->u.mmap_storage->m_len   = alloc_len;
	  inp->u.mmap_storage->m_end   = filep + alloc_len;
	  add_ref(inp->u.mmap_storage->file = inval.u.object);
	  
	  DERR(fprintf(stderr, "new mmap input (fd %d)\n", inp->fd));
	  mmapped += alloc_len;
#ifdef NB_DEBUG
	} else {
	  DERR(perror("mmap failed"));
#endif
	}
      }
#endif
      if(inp->type == NBIO_OBJ) {
	/* mmap failed or not a regular file. We'll use non-blocking IO
	 * here, to support pipes and such (which are actual fds, but can
	 * block). Typical example is CGI.
	 */
	inp->u.file = inval.u.object;
	
	if(inp->set_nb_off < 0 || inp->set_b_off < 0)
	{
	  free(inp);
	  Pike_error("set_nonblocking and/or set_blocking missing from actual file object!\n");
	}
	add_ref(inp->u.file);
	nobjects++;
	DERR(fprintf(stderr, "new input FD == %d\n", inp->fd));
      }
    }
  }
  if(inp->set_nb_off != -1 && inp->set_b_off != -1) {
    DERR(fprintf(stderr, "Resetting input object callbacks.\n"));
    push_int(0); push_int(0); push_int(0);
    apply_low(inval.u.object, inp->set_nb_off, 3);
    apply_low(inval.u.object, inp->set_b_off, 0);
    pop_n_elems(2);
  }

  ninputs++;

  if(first) {
    /* Add first in list */
    inp->next = THIS->inputs;
    THIS->inputs = inp;
  } else {
    inp->next = NULL;
    if (THIS->last_input)
      THIS->last_input->next = inp;
    else
      THIS->inputs = inp;
    THIS->last_input = inp;
  }
}
예제 #18
0
/* Our write callback */
static void f__output_write_cb(INT32 args)
{
  NBIO_INT_T written = 0, len = 0;
  char *buf = NULL;
  input *inp = THIS->inputs;

  pop_n_elems(args);
  DERR(fprintf(stderr, "output write callback\n"));
  if(THIS->buf_len) {
    /* We currently have buffered data to write */
    len = THIS->buf_len;
    buf = THIS->buf + THIS->buf_pos;
    DERR(fprintf(stderr, "Sending buffered data (%ld bytes left)\n", (long)len));
    written = do_write(THIS->buf + THIS->buf_pos, THIS->buf_len);
    switch(written) {
    case -1: /* We're done here. The write is the weakest link. Goodbye. */
    case 0:  /* Done, but because the write would block or
	      * nothing was written. I.e try again later.
	      */
      set_outp_write_cb(THIS->outp);
      return; 

    default:
      /* Write succeeded */
      THIS->buf_len -= written;
      THIS->buf_pos += written;
      if(THIS->buf_len) {
	/* We couldn't write everything. Return to try later. */
	set_outp_write_cb(THIS->outp);
	return;
      }
      
      /* We wrote all our buffered data. Just fall through to possibly
       * write more.
       */
      THIS->buf_pos = 0;
      THIS->buf_len = 0;
    }
  }
  if(inp == NULL) {
    finished();
    return;
  }
  switch(inp->type) {
  case NBIO_OBJ: /* non-blocking input - if no data available,
		  * just return. once data is available, write_cb will
		  * be called. 
		  */
    THIS->outp->mode = IDLE;
    DERR(fprintf(stderr, "Waiting for NB input data.\n"));
    if(inp->mode == SLEEPING) {
      /* Set read callback here since object is idle */
      push_callback(input_read_cb_off);
      push_int(0);
      push_callback(input_close_cb_off);
      apply_low(THIS->inputs->u.file, THIS->inputs->set_nb_off, 3);
      inp->mode = READING;
    }
    return;
    
  case NBIO_STR: 
    buf = inp->u.data->str + inp->pos;
    len = inp->len - inp->pos;
    DERR(fprintf(stderr, "Sending string data (%ld bytes left)\n", (long)len));
    written = do_write(buf, len);

    if(written >= 0) {
      inp->pos += written;
      if(inp->pos == inp->len) {
	DERR(fprintf(stderr, "Done sending string input (position == length).\n"));
	free_input(inp);
      }
      set_outp_write_cb(THIS->outp);
    }
    break;

#ifdef USE_MMAP
  case NBIO_MMAP:
    len = inp->u.mmap_storage->m_end - inp->pos;
    if(!len) {
      /* need to mmap more data. No need to check if there's more to allocate
       * since the object would have been freed in that case */
      DERR(fprintf(stderr, "mmapping more data from fd %d\n", inp->fd));
      len = MIN(inp->len - inp->pos, MAX_MMAP_SIZE);
      munmap(inp->u.mmap_storage->data, inp->u.mmap_storage->m_len);
      mmapped -= inp->u.mmap_storage->m_len;
      DERR(fprintf(stderr, "trying to mmap %ld bytes starting at pos %ld\n",
		   (long)len, (long)inp->pos));
#ifdef TEST_MMAP_FAILOVER
      inp->u.mmap_storage->data = MAP_FAILED;
#else
      inp->u.mmap_storage->data =
	(char *)mmap(0, len, PROT_READ,
		     MAP_FILE | MAP_SHARED, inp->fd,
		     inp->pos);
#endif
      if(inp->u.mmap_storage->data == MAP_FAILED) {
	struct object *tmp;
	/* FIXME: Better error handling here before falling over to
	 * normal file objects?
	 */
	DERR(perror("additional mmap failed"));
	/* converting to NBIO_OBJ */
	THIS->outp->mode = IDLE;
	tmp = inp->u.mmap_storage->file;
	free(inp->u.mmap_storage);
	inp->u.file = tmp;
#if TEST_MMAP_FAILOVER == NBIO_BLOCK_OBJ
	inp->set_nb_off = -1;	inp->set_b_off  = -1;
#else
	inp->set_nb_off = find_identifier("set_nonblocking",inp->u.file->prog);
	inp->set_b_off  = find_identifier("set_blocking", inp->u.file->prog);
#endif
	if(inp->set_nb_off < 0 || inp->set_b_off < 0)
	{
	  inp->type   = NBIO_BLOCK_OBJ; /* No set_nonblocking/set_blocking funcs */
	  inp->set_nb_off = inp->set_b_off = 0;
	  DERR(fprintf(stderr, "Converting input to NBIO_BLOCK_OBJ.\n"));
	  goto nbio_block_obj_read;
	} else {
	  DERR(fprintf(stderr, "Converting input to NBIO_OBJ.\n"));
	  inp->type   = NBIO_OBJ; /* Fake nonblocking object */
	  push_callback(input_read_cb_off);
	  push_int(0);
	  push_callback(input_close_cb_off);
	  apply_low(inp->u.file, inp->set_nb_off, 3);
	  inp->mode = READING;
	}
	nobjects++;
	break;
      } else {
	inp->u.mmap_storage->m_start = inp->pos;
	inp->u.mmap_storage->m_len   = len;
	inp->u.mmap_storage->m_end   = len + inp->pos;
	mmapped += len;
      }
    }
    buf = inp->u.mmap_storage->data +
      (inp->pos - inp->u.mmap_storage->m_start);
    DERR(fprintf(stderr,"Sending mmapped file (%ld to write, %ld total left)\n"
		 , (long)len, (long)(inp->len - inp->pos)));
    written = do_write(buf, len);

    if(written >= 0) {
      inp->pos += written;
      if(inp->pos == inp->len){
	DERR(fprintf(stderr, "Done sending mmapped input (position == length).\n"));

	free_input(inp);
      }
      set_outp_write_cb(THIS->outp);
    }
#endif
    break;
    
  case NBIO_BLOCK_OBJ:
  nbio_block_obj_read:
    {
      int read;
      read = read_data(); /* At this point we have no data, so read some */
      switch(read) {
      case  -1:
	/* We are done. No more inputs */
	finished();
	return;
      case -2: /* Invalid input for read_data == redo this function */
      case -3: /* We read from a fake object and got a string == redo */
	f__output_write_cb(0);
	return;
      }
      len = THIS->buf_len;
      buf = THIS->buf;
      DERR(fprintf(stderr, "Sending buffered data (%ld bytes left)\n", (long)len));
      written = do_write(buf, len);
      if(written >= 0) {
	THIS->buf_len -= written;
	THIS->buf_pos += written;
	set_outp_write_cb(THIS->outp);
      }
    }
  }   
  if(written < 0) {
    return;
  } 
  if(!THIS->buf_len && THIS->inputs == NULL) {
    finished();
  }
}
예제 #19
0
/* This function reads some data from the current input (file object)
 */
static INLINE int read_data(void)
{
  int buf_size = READ_BUFFER_SIZE;
  NBIO_INT_T to_read  = 0;
  char *rd;
  input *inp;
 redo:
  DERR(fprintf(stderr, "Reading from blocking input.\n"));
  THIS->buf_pos = 0;
  inp = THIS->inputs;
  if(inp == NULL)
    return -1; /* No more inputs */
  if(inp->type != NBIO_BLOCK_OBJ)
    return -2; /* invalid input for read_data */
  if(inp->fd != -1) {
    char * ptr;
    DERR(fprintf(stderr, "Reading from real fd.\n"));
	
    if(inp->len != -1) 
      to_read = MIN(buf_size, inp->len - inp->pos);
    else
      to_read = buf_size;
    if(THIS->buf == NULL || THIS->buf_size < to_read) {
      alloc_data_buf(to_read);
    }
	
    ptr = THIS->buf;
    THREADS_ALLOW();
    to_read = fd_read(inp->fd, ptr, to_read);
    THREADS_DISALLOW();
    DERR(fprintf(stderr, "read %ld from file\n", (long)to_read));
  } else {
    DERR(fprintf(stderr, "Reading from fake fd.\n"));
    if(inp->len != -1 && inp->pos >= inp->len) {
      /* We are done reading from this one */
      DERR(fprintf(stderr, "Data done from fake fd.\n"));
      free_input(inp);
      goto redo; /* goto == ugly, but we want to read the next input
		  * if any
		  */
    }	

    to_read = READ_BUFFER_SIZE;
    push_int(to_read);
    push_int(1);
    apply_low(inp->u.file, inp->read_off, 2);
    if(Pike_sp[-1].type == T_STRING) {
      if(Pike_sp[-1].u.string->len == 0) {
	DERR(fprintf(stderr, "Read zero bytes from fake fd (EOF).\n"));
	to_read = 0;
      } else {
	new_input(Pike_sp[-1], 0, 1);
	to_read = THIS->inputs->len;
	inp->pos += to_read;
 	DERR(fprintf(stderr, "read %ld bytes from fake file\n",
		     (long)to_read));
	pop_stack();
	return -3; /* Got a string buffer appended to the input list */
      }
    } else if(Pike_sp[-1].type == T_INT && Pike_sp[-1].u.integer == 0) {
      to_read = 0;
    } else {
      Pike_error("Incorrect result from read, expected string.\n");
    }
    pop_stack();
  }
  switch(to_read) {
  case 0: /* EOF */
    DERR(fprintf(stderr, "read zero blocking bytes == EOF\n"));
    free_input(inp);
    break;

  case -1:
    if(errno != EAGAIN) {
      /* Got an error. Free input and continue */
      DERR(perror("Error while reading:"));
      free_input(inp); 
    }
    goto redo;

  default:
    inp->pos += to_read;
    if(inp->pos == inp->len) {
      DERR(fprintf(stderr, "Done reading (position == length).\n"));
      free_input(inp);
    }
    THIS->buf_len = to_read;
    break;
  }
  return to_read;
}