pike.git / src / post_modules / Shuffler / Shuffler.cmod

version» Context lines:

pike.git/src/post_modules/Shuffler/Shuffler.cmod:20:   #include "array.h"   #include "builtin_functions.h"   #include "bignum.h"      #include "shuffler.h"   #include "sources.h"      DECLARATIONS      #if 0 - #include <stdio.h> +    #define SHUFFLE_DEBUG1(fmt, arg1) fprintf(stderr,"Shuffle[%p]:" fmt, arg1)   #define SHUFFLE_DEBUG2(fmt, arg1, arg2) fprintf(stderr,"Shuffle[%p]:" fmt, arg1, arg2)   #define SHUFFLE_DEBUG3(fmt, arg1, arg2, arg3) fprintf(stderr,"Shuffle[%p]:" fmt, arg1, arg2, arg3)   #define SHUFFLE_DEBUG4(fmt, arg1, arg2, arg3, arg4) fprintf(stderr,"Shuffle[%p]:" fmt, arg1, arg2, arg3, arg4)   #else   #define SHUFFLE_DEBUG1(fmt, arg1)   #define SHUFFLE_DEBUG2(fmt, arg1, arg2)   #define SHUFFLE_DEBUG3(fmt, arg1, arg2, arg3)   #define SHUFFLE_DEBUG4(fmt, arg1, arg2, arg3, arg4)   #endif   #define BLOCK 8192   static void free_source( struct source *s )   {    debug_malloc_touch(s);    if( s->free_source ) s->free_source( s );    free( s );   }    - extern struct program *Shuffler_program; -  +    /*! @module Shuffler -  +  *! +  *! Module implementing sending to and from nonblocking streams and other sources. +  *! +  *! Most useful when implementing sending of data from strings, files and +  *! other sources to a network connection. The module also supports +  *! generic bandwidth throttling. +  *! +  *! Multiple @[Shuffler] object can be created, each optionally with +  *! their own backend. +  *! +  *! This makes it easier to use more than one CPU for pure data +  *! transmission, just have multiple backends each in their own +  *! thread, with their own shuffle object. +  *!    */      /*! @class Throttler    *!    *! @note    *! This is an interface that all @[Throttler]s must implement.    *! It's not an actual class in this module.    *!    *! @decl void request( Shuffle shuffle, int amount, function(int:void) callback )    *! This function is called when the @[Shuffle] wants to send some    *! data to a client.    *!    *! When data can be sent, the @[callback] function should be called    *! with the amount of data that can be sent as the argument.    *!    *! @decl void give_back( Shuffle shuffle, int amount ) -  +  *!    *! This function will be called by the @[Shuffle] object to report    *! that some data assigned to it by this throttler was unusued, and    *! can be given to another @[Shuffle] object instead.    */   /*! @endclass    */      /*! @class Shuffle    *! This class contains the state for one ongoing data    *! shuffling operation. To create a @[Shuffle] instance, use the
pike.git/src/post_modules/Shuffler/Shuffler.cmod:162:    */    optflags OPT_SIDE_EFFECT;    {    SHUFFLE_DEBUG2("set_throttler(%p)\n", THIS, t );    if( THIS->throttler )    free_object( THIS->throttler );    if( (THIS->throttler = t) ) {    debug_malloc_touch(THIS->throttler);    Pike_sp--;    } -  else -  pop_stack(); -  push_int(0); +     }       PIKEFUN int sent_data()    /*! @decl int sent_data()    *! Returns the amount of data that has been sent so far.    *!    */    optflags OPT_TRY_OPTIMIZE;    {    SHUFFLE_DEBUG2("sent_data() --> %d\n", THIS, THIS->sent );
pike.git/src/post_modules/Shuffler/Shuffler.cmod:538:    else    {    t->leftovers.len -= sent;    t->leftovers.off += sent;    }    }    if( sent < amount )    _give_back( t, amount-sent );    }    -  /*! @decl void send_more_callback( int amount ) -  */ +  /* internal use.. */    PIKEFUN void send_more_callback( int amount )    optflags OPT_SIDE_EFFECT;    {    SHUFFLE_DEBUG2("send_more_callback(%d)\n", THIS,amount );    if( THIS->state == RUNNING )    {    __set_callbacks( THIS );    __send_more_callback( THIS, amount );    }    else    _give_back( THIS, amount );    }    -  /*! @decl void write_callback( mixed|void x ) -  */ +  /* internal use.. */    PIKEFUN void write_callback( mixed|void x )    optflags OPT_SIDE_EFFECT;    {    SHUFFLE_DEBUG1("write_callback()\n", THIS );    _send_more( THIS );    }       /*! @decl void create(object fd, object shuffler, mixed throttler,@    *! mixed backend) -  +  *! +  *! This object is normally not created directly, instead use +  *! @[Shuffler()->shuffle]    */    PIKEFUN void create( object fd,    object shuffler,    mixed throttler,    mixed backend )    flags ID_PROTECTED;    {    struct Backend_struct *be = default_backend;       if( (args != 4) || !shuffler || !get_storage( shuffler, Shuffler_program ) )
pike.git/src/post_modules/Shuffler/Shuffler.cmod:592:    if( TYPEOF(*throttler) == PIKE_T_OBJECT )    {    THIS->throttler = throttler->u.object;    add_ref(THIS->throttler);    }       if (find_identifier("release_fd", fd->prog) < 0)    change_fd_for_box(&THIS->box, -1);    else {    safe_apply( fd, "release_fd", 0 ); +  args++;    if(TYPEOF(*backend) == PIKE_T_OBJECT && backend->u.object) { -  be = (struct Backend_struct*) -  get_storage(backend->u.object, Backend_program); +  be = get_storage(backend->u.object, Backend_program);    if (!be) { -  SIMPLE_BAD_ARG_ERROR("Shuffle->create()", 4, +  SIMPLE_ARG_TYPE_ERROR("Shuffle->create()", 4,    "object(Pike.__Backend)");    }    }    change_fd_for_box(&THIS->box, Pike_sp[-1].u.integer); -  pop_stack(); +     }       if( THIS->box.fd >= 0 )    {    set_nonblocking( THIS->box.fd, 1 );    if(THIS->box.backend) {    /* FIXME: Ought to change backend to be here. */    set_fd_callback_events(&THIS->box, 0, 0);    } else    INIT_FD_CALLBACK_BOX(&THIS->box, be, THIS->box.ref_obj,    THIS->box.fd, 0, got_shuffler_event, 0);    }    else    {    push_int( 0 ); /* read */    push_int( 0 ); /* write */    push_int( 0 ); /* close */    safe_apply( THIS->file_obj, "set_nonblocking", 3 ); -  pop_stack(); +  args++;    } -  -  pop_n_elems( args ); -  push_int(0); +  pop_n_elems(args);    }       PIKEFUN void start()    /*! @decl void start();    *! Start sending data from the sources.    *!    */    optflags OPT_SIDE_EFFECT;    {    if( !THIS->file_obj )
pike.git/src/post_modules/Shuffler/Shuffler.cmod:675:    /*! @decl void add_source( mixed source, int|void start, int|void length );    *! Add a new source to the list of data sources.    *! The data from the sources will be sent in order.    *!    *! If start and length are not specified, the whole source will be    *! sent, if start but not length is specified, the whole source,    *! excluding the first @[start] bytes will be sent.    *!    *! Currently supported sources    *! @dl -  *! @item String +  *! @item string    *! An ordinary 8-bit wide pike string. -  *! @item Memory +  *! @item System.Memory    *! An initialized instance of the System.Memory class. -  *! @item NormalFile +  *! @item Stdio.File    *! Stdio.File instance pointing to a normal file. -  *! @item Stream +  *! @item Stdio.Stream    *! Stdio.File instance pointing to a stream of some kind -  *! (network socket, named pipe, stdin etc). -  *! @item Pike-stream -  *! Stdio.File lookalike with read callback support +  *! (network socket, named pipe, stdin etc). Blocking or nonblocking. +  *! @item Stdio.NonblockingStream|Stdio.Stream +  *! An object implementing the callback based reading    *! (set_read_callback and set_close_callback).    *! @enddl    */    optflags OPT_SIDE_EFFECT;    {    INT64 rstart=0, rlength=-1;    struct source *res;       if( !THIS->file_obj )    Pike_error("Cannot add source, no destination.\n");    -  if( args > 1 ) +  if( start )    {    if( TYPEOF(*start) == PIKE_T_OBJECT )    int64_from_bignum( &rstart, start->u.object );    else if( TYPEOF(*start) == PIKE_T_INT && !SUBTYPEOF(*start) )    rstart = start->u.integer;    } -  if( args > 2 ) +  if( length )    {    if( TYPEOF(*length) == PIKE_T_OBJECT )    int64_from_bignum( &rlength, length->u.object );    else if( TYPEOF(*length) == PIKE_T_INT && !SUBTYPEOF(*length) )    rlength = length->u.integer; -  } +     if( rlength == 0 ) -  { -  pop_n_elems(args); -  push_int(0); +     return;    }    debug_malloc_touch( source );       res = source_make( source, rstart, rlength );       debug_malloc_touch( res );       SHUFFLE_DEBUG4("add_source(XX,%d,%d) --> %p\n", THIS,    (int)rstart, (int)rlength, res );
pike.git/src/post_modules/Shuffler/Shuffler.cmod:737:       res->next = NULL;    if( THIS->current_source )    {    THIS->last_source->next = res;    THIS->last_source = res;    }    else {    THIS->current_source = THIS->last_source = res;    } -  pop_n_elems(args); -  push_int(0); +     }   }      /*! @endclass    */      /*! @class Shuffler    *!    *! A data shuffler. An instance of this class handles a list of    *! @[Shuffle] objects. Each @[Shuffle] object can send data from one
pike.git/src/post_modules/Shuffler/Shuffler.cmod:762:      PIKECLASS Shuffler   {    PIKEVAR object backend;    PIKEVAR object throttler;       CVAR int paused;       PIKEVAR array sources;    -  static void update_sources() +  static void update_sources(void)    {    push_array( THIS->sources );    debug_malloc_touch( THIS->sources );    push_int(0);    f_aggregate(1);    o_subtract();    THIS->sources = Pike_sp[-1].u.array;    debug_malloc_touch( THIS->sources );    Pike_sp--;    }
pike.git/src/post_modules/Shuffler/Shuffler.cmod:787:    *! Set the backend that will be used by all @[Shuffle] objects created    *! from this shuffler.    *!    */    {    if( THIS->backend )    free_object( THIS->backend );    THIS->backend = b;    debug_malloc_touch( THIS->backend );    Pike_sp--; -  push_int(0); +     }       PIKEFUN void set_throttler( object|void t )    /*! @decl void set_throttler( Throttler t );    *! Set the throttler that will be used in all @[Shuffle] objects    *! created from this shuffler, unless overridden in the    *! @[Shuffle] objects.    *!    */    {    if( THIS->throttler )    free_object( THIS->throttler );    debug_malloc_pass( THIS->throttler = t );    Pike_sp--; -  push_int(0); +     }       PIKEFUN void pause()    /*! @decl void pause();    *! Pause all @[Shuffle] objects associated with this @[Shuffler]    *!    */    {    int i;    update_sources();
pike.git/src/post_modules/Shuffler/Shuffler.cmod:848:       PIKEFUN void ___remove_shuffle( object so )    {    f_aggregate(1);    push_array( THIS->sources );    stack_swap();    o_subtract();    THIS->sources = Pike_sp[-1].u.array;    debug_malloc_touch( THIS->sources );    Pike_sp--; -  push_int(0); +     }       PIKEFUN object shuffle( object destination ) -  /*! @decl Shuffle shuffle( Stdio.File destination ); +  /*! @decl Shuffle shuffle( Stdio.NonblockingStream destination );    *! Create a new @[Shuffle] object.    *! -  +  *! The destination has to support nonblocking I/O.    */    {    ref_push_object( Pike_fp->current_object ); /* shuffler */    if( THIS->throttler )    ref_push_object( THIS->throttler );    else    push_int( 0 );    if( THIS->backend )    ref_push_object( THIS->backend );    else
pike.git/src/post_modules/Shuffler/Shuffler.cmod:894:   /*! @endclass    */      /*! @decl constant INITIAL;    *! @decl constant RUNNING;    *! @decl constant PAUSED;    *! @decl constant DONE;    *! @decl constant WRITE_ERROR;    *! @decl constant READ_ERROR;    *! @decl constant USER_ABORT; +  *! The state of an individual @[Shuffle] object.    */      /*! @endmodule    */      PIKE_MODULE_INIT   {    INIT;    sources_init();    add_integer_constant( "INITIAL", INITIAL, 0 );