e576bb2002-10-11Martin Nilsson /* -*- c -*- || 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. */
08d6302002-10-10Martin Nilsson 
dd3c382002-05-29Per Hedbor #include "global.h" #include "stralloc.h" #include "pike_macros.h" #include "interpret.h"
74bd242002-07-03Per Hedbor #include "threads.h"
dd3c382002-05-29Per Hedbor #include "program.h" #include "program_id.h" #include "object.h" #include "operators.h" #include "fdlib.h" #include "fd_control.h" #include "backend.h" #include "module_support.h" #include "array.h" #include "builtin_functions.h"
056bf92004-03-20Henrik Grubbström (Grubba) #include "bignum.h"
dd3c382002-05-29Per Hedbor  #include "shuffler.h" #include "sources.h"
56c0642008-07-31Martin Stjernholm DECLARATIONS
bb66712002-07-04Per Hedbor #if 0
74bd242002-07-03Per Hedbor #include <stdio.h>
94d29e2002-08-13Henrik Grubbström (Grubba) #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)
74bd242002-07-03Per Hedbor #else
94d29e2002-08-13Henrik Grubbström (Grubba) #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)
74bd242002-07-03Per Hedbor #endif
dd3c382002-05-29Per Hedbor #define BLOCK 8192 static void free_source( struct source *s ) {
b2986f2002-07-05Per Hedbor  debug_malloc_touch(s);
3387322002-05-29Per Hedbor  if( s->free_source ) s->free_source( s );
dd3c382002-05-29Per Hedbor  free( s ); } extern struct program *Shuffler_program;
1961162002-06-24Per Hedbor /*! @module Shuffler */ /*! @class Throttler *!
9439d22002-06-26Manual system  *! @note
1961162002-06-24Per Hedbor  *! This is an interface that all @[Throttler]s must implement. *! It's not an actual class in this module. *!
b00ab92002-06-26Per Hedbor  *! @decl void request( Shuffle shuffle, int amount, function(int:void) callback )
1961162002-06-24Per Hedbor  *! 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. *!
9439d22002-06-26Manual system  *! @decl void give_back( Shuffle shuffle, int amount )
1961162002-06-24Per Hedbor  *! 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.
056bf92004-03-20Henrik Grubbström (Grubba)  */ /*! @endclass
1961162002-06-24Per Hedbor  */
dd3c382002-05-29Per Hedbor /*! @class Shuffle
1961162002-06-24Per Hedbor  *! This class contains the state for one ongoing data *! shuffling operation. To create a @[Shuffle] instance, use the *! @[Shuffler()->shuffle] method. *!
dd3c382002-05-29Per Hedbor  */ PIKECLASS Shuffle {
85c1122004-06-27Stephen R. van den Berg  CVAR struct fd_callback_box box;
dd3c382002-05-29Per Hedbor  PIKEVAR object shuffler; /*! @decl Shuffler shuffler; *! The @[Shuffler] that owns this @[Shuffle] object
1961162002-06-24Per Hedbor  *!
dd3c382002-05-29Per Hedbor  */ PIKEVAR object throttler; /*! @decl Throttler throttler; *! The @[Throttler] that is associated with this @[Shuffle] object, *! if any.
1961162002-06-24Per Hedbor  *!
dd3c382002-05-29Per Hedbor  */ PIKEVAR mixed done_callback;
74bd242002-07-03Per Hedbor  PIKEVAR mixed request_arg;
dd3c382002-05-29Per Hedbor  CVAR struct source *current_source; CVAR struct source *last_source; CVAR struct object *file_obj; CVAR int callback;
80439d2004-06-29Stephen R. van den Berg  CVAR int write_callback;
dd3c382002-05-29Per Hedbor  CVAR int sent; CVAR ShuffleState state; CVAR struct data leftovers;
d7de8f2002-05-29Per Hedbor 
85c1122004-06-27Stephen R. van den Berg  static void _send_more( struct Shuffle_struct *t );
d7de8f2002-05-29Per Hedbor  static void __set_callbacks( struct Shuffle_struct *t ) {
85c1122004-06-27Stephen R. van den Berg  SHUFFLE_DEBUG2("__set_calllbacks(%s)\n", t,(t->box.fd>0?"C":"Pike") );
80439d2004-06-29Stephen R. van den Berg  if( t->box.fd >= 0 )
ca6bd02012-05-01Bill Welliver  set_fd_callback_events(&t->box, PIKE_BIT_FD_WRITE, 0);
80439d2004-06-29Stephen R. van den Berg  else if( t->file_obj && t->file_obj->prog ) {
017b572011-10-28Henrik Grubbström (Grubba)  ref_push_function( t->box.ref_obj, t->write_callback );
80439d2004-06-29Stephen R. van den Berg  safe_apply( t->file_obj, "set_write_callback", 1 ); pop_stack(); }
a69d662004-08-27Martin Nilsson  else {
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG1("EEP: No destination! Cannot set callbacks\n",t);
a69d662004-08-27Martin Nilsson  }
d7de8f2002-05-29Per Hedbor  } static void __remove_callbacks( struct Shuffle_struct *t ) {
85c1122004-06-27Stephen R. van den Berg  SHUFFLE_DEBUG2("__remove_calllbacks(%s)\n", t, (t->box.fd>=0?"C":"Pike") );
80439d2004-06-29Stephen R. van den Berg  if( t->box.fd >= 0 )
ca6bd02012-05-01Bill Welliver  set_fd_callback_events(&t->box, 0, 0);
80439d2004-06-29Stephen R. van den Berg  else if( t->file_obj && t->file_obj->prog ) { push_int(0); safe_apply( t->file_obj, "set_write_callback", 1 ); pop_stack(); }
a69d662004-08-27Martin Nilsson  else {
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG1("EEP: No destination! Cannot remove callbacks\n",t);
a69d662004-08-27Martin Nilsson  }
d7de8f2002-05-29Per Hedbor  }
74dfe82012-12-30Jonas Walldén  static int got_shuffler_event(struct fd_callback_box*box, int DEBUGUSED(event)) {
85c1122004-06-27Stephen R. van den Berg #ifdef PIKE_DEBUG if (event != PIKE_FD_WRITE) Pike_fatal ("Got unexpected event %d.\n", event); #endif _send_more((struct Shuffle_struct*) ((char*)box-offsetof(struct Shuffle_struct,box)));
cbb4e72013-05-31Martin Nilsson  return 0; // Everything OK.
85c1122004-06-27Stephen R. van den Berg  }
dd3c382002-05-29Per Hedbor  PIKEFUN void set_throttler( object t ) /*! @decl void set_throttler(Throttler t) *! Calling this function overrides the @[Shuffler] global throttler.
1961162002-06-24Per Hedbor  *!
dd3c382002-05-29Per Hedbor  */
2e1e0b2004-04-04Martin Nilsson  optflags OPT_SIDE_EFFECT;
dd3c382002-05-29Per Hedbor  {
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG2("set_throttler(%p)\n", THIS, t );
dd3c382002-05-29Per Hedbor  if( THIS->throttler ) free_object( THIS->throttler );
7f7f792008-08-12Martin Stjernholm  if( (THIS->throttler = t) ) {
f12f5a2008-08-07Stephen R. van den Berg  debug_malloc_touch(THIS->throttler); Pike_sp--; } else pop_stack();
dd3c382002-05-29Per Hedbor  push_int(0); } PIKEFUN int sent_data() /*! @decl int sent_data() *! Returns the amount of data that has been sent so far.
1961162002-06-24Per Hedbor  *!
dd3c382002-05-29Per Hedbor  */
2e1e0b2004-04-04Martin Nilsson  optflags OPT_TRY_OPTIMIZE;
dd3c382002-05-29Per Hedbor  {
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG2("sent_data() --> %d\n", THIS, THIS->sent );
dd3c382002-05-29Per Hedbor  RETURN THIS->sent; } PIKEFUN int state() /*! @decl int state() *! Returns the current state of the shuffler. *! This is one of the following:
1961162002-06-24Per Hedbor  *! @[INITIAL], *! @[RUNNING], *! @[PAUSED], *! @[DONE], *! @[WRITE_ERROR], *! @[READ_ERROR] and
dd3c382002-05-29Per Hedbor  *! @[USER_ABORT]
1961162002-06-24Per Hedbor  *!
dd3c382002-05-29Per Hedbor  */
2e1e0b2004-04-04Martin Nilsson  optflags OPT_TRY_OPTIMIZE;
dd3c382002-05-29Per Hedbor  {
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG2("state() --> %d\n", THIS, THIS->state );
dd3c382002-05-29Per Hedbor  RETURN THIS->state; } INIT { THIS->leftovers.do_free = 0; THIS->shuffler = 0; THIS->throttler = 0;
74bd242002-07-03Per Hedbor  THIS->sent = 0;
1ab4ac2008-01-26Martin Stjernholm  mark_free_svalue (&THIS->done_callback);
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(THIS->request_arg, PIKE_T_INT, NUMBER_NUMBER, integer, 0);
dd3c382002-05-29Per Hedbor  THIS->leftovers.len = 0; THIS->current_source = NULL; THIS->file_obj = NULL; THIS->state = INITIAL; THIS->callback = find_identifier("send_more_callback",Pike_fp->current_object->prog);
80439d2004-06-29Stephen R. van den Berg  THIS->write_callback = find_identifier("write_callback",Pike_fp->current_object->prog);
930bff2010-06-22Henrik Grubbström (Grubba)  INIT_FD_CALLBACK_BOX(&THIS->box, NULL, Pike_fp->current_object, -1,
ca6bd02012-05-01Bill Welliver  0, got_shuffler_event, 0);
85c1122004-06-27Stephen R. van den Berg  debug_malloc_touch(THIS->box.ref_obj);
d7de8f2002-05-29Per Hedbor 
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG1("init()\n", THIS );
dd3c382002-05-29Per Hedbor  } EXIT {
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG1("exit()\n", THIS );
4945cb2004-07-02Stephen R. van den Berg  if(THIS->box.fd >= 0) { push_int( THIS->box.fd );
85c1122004-06-27Stephen R. van den Berg  unhook_fd_callback_box(&THIS->box);
4945cb2004-07-02Stephen R. van den Berg  if(THIS->file_obj) safe_apply( THIS->file_obj, "take_fd", 1 ); pop_stack();
85c1122004-06-27Stephen R. van den Berg  }
4945cb2004-07-02Stephen R. van den Berg 
74bd242002-07-03Per Hedbor  if( THIS->file_obj ) { free_object( THIS->file_obj ); THIS->file_obj = 0; }
dd3c382002-05-29Per Hedbor  while( THIS->current_source ) { struct source *n = THIS->current_source->next; free_source( THIS->current_source ); THIS->current_source = n; } if( THIS->leftovers.data && THIS->leftovers.do_free )
b2986f2002-07-05Per Hedbor  { debug_malloc_touch(THIS->leftovers.data);
dd3c382002-05-29Per Hedbor  free( THIS->leftovers.data );
dd196c2007-03-06H. William Welliver III  THIS->leftovers.data = NULL;
fc5b3f2007-11-10Martin Nilsson  THIS->leftovers.do_free = 0;
b2986f2002-07-05Per Hedbor  }
dd3c382002-05-29Per Hedbor  } static void __send_more_callback( struct Shuffle_struct *t, int amount ); static void _request( struct Shuffle_struct *t, int amount ) {
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG3("_request(%d) from %p\n", t, amount, t->throttler );
bb66712002-07-04Per Hedbor  if( t->throttler && t->throttler->prog )
dd3c382002-05-29Per Hedbor  {
d7de8f2002-05-29Per Hedbor  __remove_callbacks( t );
b2986f2002-07-05Per Hedbor  debug_malloc_touch( t->throttler );
85c1122004-06-27Stephen R. van den Berg  debug_malloc_touch( t->box.ref_obj ); ref_push_object( t->box.ref_obj );
dd3c382002-05-29Per Hedbor  push_int( amount );
017b572011-10-28Henrik Grubbström (Grubba)  ref_push_function( t->box.ref_obj, t->callback );
74bd242002-07-03Per Hedbor  push_svalue( &t->request_arg ); safe_apply( t->throttler, "request", 4 );
dd3c382002-05-29Per Hedbor  pop_stack(); } else /* bypass the pike function calling for the case * when no throttling is done */ __send_more_callback( t, amount ); }
85c1122004-06-27Stephen R. van den Berg  static void _send_more( struct Shuffle_struct *t )
dd3c382002-05-29Per Hedbor  { int l = BLOCK;
85c1122004-06-27Stephen R. van den Berg  SHUFFLE_DEBUG2("_send_more(%d)\n", t, t->box.fd );
a20daf2004-06-23Stephen R. van den Berg  if( t->leftovers.len > 0 )
dd3c382002-05-29Per Hedbor  l = t->leftovers.len; _request( t, l ); } static void _set_callbacks( struct Shuffle_struct *t ) {
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG1("_set_callbacks()\n", t );
dd3c382002-05-29Per Hedbor  if( t->current_source && t->current_source->setup_callbacks ) t->current_source->setup_callbacks( t->current_source );
d7de8f2002-05-29Per Hedbor  __set_callbacks( t );
dd3c382002-05-29Per Hedbor  } static void _remove_callbacks( struct Shuffle_struct *t ) {
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG1("_remove_callbacks()\n",t );
dd3c382002-05-29Per Hedbor  if( t->current_source && t->current_source->remove_callbacks ) t->current_source->remove_callbacks( t->current_source );
d7de8f2002-05-29Per Hedbor  __remove_callbacks( t );
dd3c382002-05-29Per Hedbor  } static void _all_done( struct Shuffle_struct *t, int reason ) {
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG2("_all_done(%d)\n", t,reason );
9586542002-11-24Marcus Agehall  /* We should set the reason for being done first of all */ switch( reason ) { case 0: t->state = DONE; break; case 1: t->state = WRITE_ERROR; break; case 2: t->state = USER_ABORT; break; case 3: t->state = READ_ERROR; break; }
85c1122004-06-27Stephen R. van den Berg  /* Remove our callbacks. */ _remove_callbacks( t );
4945cb2004-07-02Stephen R. van den Berg  if(t->box.fd >= 0) { push_int( t->box.fd );
85c1122004-06-27Stephen R. van den Berg  unhook_fd_callback_box(&t->box);
7e88552008-07-15Henrik Grubbström (Grubba)  t->box.fd = -1;
4945cb2004-07-02Stephen R. van den Berg  if(t->file_obj) safe_apply(t->file_obj, "take_fd", 1 ); pop_stack();
85c1122004-06-27Stephen R. van den Berg  }
4945cb2004-07-02Stephen R. van den Berg  debug_malloc_touch( t->box.ref_obj ); ref_push_object( t->box.ref_obj );
85c1122004-06-27Stephen R. van den Berg 
bb66712002-07-04Per Hedbor  /* It might have been destroyed. */
b2986f2002-07-05Per Hedbor  if( t->shuffler && t->shuffler->prog ) { debug_malloc_touch( t->shuffler );
bb66712002-07-04Per Hedbor  safe_apply( t->shuffler, "___remove_shuffle", 1 );
b2986f2002-07-05Per Hedbor  }
dd3c382002-05-29Per Hedbor  pop_stack();
9586542002-11-24Marcus Agehall  /* Destroy file_obj if any. */
74bd242002-07-03Per Hedbor  if( t->file_obj )
dd3c382002-05-29Per Hedbor  {
b2986f2002-07-05Per Hedbor  debug_malloc_touch( t->file_obj );
74bd242002-07-03Per Hedbor  free_object( t->file_obj ); t->file_obj = 0;
dd3c382002-05-29Per Hedbor  }
9586542002-11-24Marcus Agehall  /* Destroy all our sources. */
74bd242002-07-03Per Hedbor  while( t->current_source )
dd3c382002-05-29Per Hedbor  {
74bd242002-07-03Per Hedbor  struct source *n = t->current_source->next;
b2986f2002-07-05Per Hedbor  debug_malloc_touch( t->current_source );
74bd242002-07-03Per Hedbor  free_source( t->current_source ); t->current_source = n;
dd3c382002-05-29Per Hedbor  }
9586542002-11-24Marcus Agehall  /* Free any data left in pipe. */
74bd242002-07-03Per Hedbor  if( t->leftovers.data && t->leftovers.do_free )
b2986f2002-07-05Per Hedbor  { debug_malloc_touch( t->leftovers.data );
74bd242002-07-03Per Hedbor  free( t->leftovers.data );
dd196c2007-03-06H. William Welliver III  t->leftovers.data = NULL;
fc5b3f2007-11-10Martin Nilsson  t->leftovers.do_free = 0;
b2986f2002-07-05Per Hedbor  }
dd3c382002-05-29Per Hedbor 
74bd242002-07-03Per Hedbor  t->leftovers.data = 0;
cf655a2013-08-02Arne Goedeke  /* If a callback exists, we call it at the end, because done_callback might * explicitly destruct this object. This happened in one of the testcases. * Calling done_callback at the end essentially reverts commit * 95865471b36a441ad345cd7f23fe7d3260578c2f. * /arne */ if( TYPEOF(t->done_callback) != PIKE_T_FREE ) { SHUFFLE_DEBUG3("_all_done(%d): Calling done callback: %p\n", t, reason, t->done_callback.u.object); push_svalue( &t->done_callback ); /* Ensure us only calling the callback once. */ free_svalue(&t->done_callback); mark_free_svalue(&t->done_callback); ref_push_object( t->box.ref_obj ); push_int( reason ); apply_svalue( Pike_sp-3, 2 ); pop_stack(); pop_stack(); }
dd3c382002-05-29Per Hedbor  } PIKEFUN void set_done_callback( mixed cb ) /*! @decl void set_done_callback( function(Shuffle,int:void) cb ) *! Sets the done callback. This function will be called when all *! sources have been processed, or if an error occurs.
1961162002-06-24Per Hedbor  *!
dd3c382002-05-29Per Hedbor  */
2e1e0b2004-04-04Martin Nilsson  optflags OPT_SIDE_EFFECT;
dd3c382002-05-29Per Hedbor  {
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG2("set_done_callback(%p)\n", THIS, cb->u.object );
dd3c382002-05-29Per Hedbor  assign_svalue( &THIS->done_callback,cb);
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(THIS->done_callback) == PIKE_T_INT)
1ab4ac2008-01-26Martin Stjernholm  mark_free_svalue (&THIS->done_callback);
dd3c382002-05-29Per Hedbor  }
74bd242002-07-03Per Hedbor  PIKEFUN void set_request_arg( mixed arg ) /*! @decl void set_request_arg( mixed arg ) *!
b0430a2002-11-26Henrik Grubbström (Grubba)  *! Sets the extra argument sent to @[Throttler()->request()] and
74bd242002-07-03Per Hedbor  *! @[Throttler()->give_back]. *! */
2e1e0b2004-04-04Martin Nilsson  optflags OPT_SIDE_EFFECT;
74bd242002-07-03Per Hedbor  {
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG2("set_request_arg(%p)\n", THIS, arg->u.object );
74bd242002-07-03Per Hedbor  assign_svalue( &THIS->request_arg, arg ); }
dd3c382002-05-29Per Hedbor  static void _give_back( struct Shuffle_struct *t, int amount ) {
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG2("_give_back(%d)\n", t, amount );
bb66712002-07-04Per Hedbor  if( t->throttler && t->throttler->prog )
dd3c382002-05-29Per Hedbor  {
85c1122004-06-27Stephen R. van den Berg  ref_push_object( t->box.ref_obj ); debug_malloc_touch( t->box.ref_obj );
b2986f2002-07-05Per Hedbor  debug_malloc_touch( t->throttler );
dd3c382002-05-29Per Hedbor  push_int( amount );
74bd242002-07-03Per Hedbor  push_svalue( &t->request_arg ); safe_apply( t->throttler, "give_back", 3 );
dd3c382002-05-29Per Hedbor  pop_stack(); } } static void __send_more_callback( struct Shuffle_struct *t, int amount ) {
74bd242002-07-03Per Hedbor  int sent = 0;
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG2("__send_more_callback(%d)\n", t, amount );
7286ad2002-05-30Per Hedbor  while( t->leftovers.len < 1 )
dd3c382002-05-29Per Hedbor  { while( t->current_source && t->current_source->eof ) { struct source *n = t->current_source->next;
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG2("__send_more_callback(): source done: %p\n", t, t->current_source );
dd3c382002-05-29Per Hedbor  if( t->current_source->remove_callbacks ) t->current_source->remove_callbacks( t->current_source ); free_source( t->current_source ); t->current_source = n;
32de532002-05-30Per Hedbor  if( n && n->setup_callbacks ) n->setup_callbacks( n );
dd3c382002-05-29Per Hedbor  } if( !t->current_source ) {
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG1("__send_more_callback(): no sources\n", t );
dd3c382002-05-29Per Hedbor  _give_back( t, amount ); _all_done( t, 0 ); return; }
74bd242002-07-03Per Hedbor  t->leftovers = t->current_source->get_data( t->current_source, MAXIMUM(amount,8192) );
32de532002-05-30Per Hedbor 
dd3c382002-05-29Per Hedbor  if( t->leftovers.len == -2 ) { /* come back later (nonblocking source without more data to read) */
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG1("__send_more_callback(): read pending\n", t );
7286ad2002-05-30Per Hedbor  __remove_callbacks( t ); t->current_source->set_callback( t->current_source, (void *)_set_callbacks, t );
dd3c382002-05-29Per Hedbor  _give_back( t, amount ); return; } else if( t->leftovers.len < 0 ) {
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG1("__send_more_callback(): read error\n", t );
dd3c382002-05-29Per Hedbor  /* read error */ _give_back( t, amount ); _all_done( t, 3 ); return; } } /* Now it's time to actually send the data. */
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG2("__send_more_callback(): sending(%d)\n", t,
74bd242002-07-03Per Hedbor  MINIMUM(amount,t->leftovers.len));
bb66712002-07-04Per Hedbor  sent = -1;
85c1122004-06-27Stephen R. van den Berg  if( t->box.fd >= 0 )
74bd242002-07-03Per Hedbor  { THREADS_ALLOW();
85c1122004-06-27Stephen R. van den Berg  sent = fd_write( t->box.fd, t->leftovers.data+t->leftovers.off,
d7de8f2002-05-29Per Hedbor  MINIMUM(amount,t->leftovers.len) );
74bd242002-07-03Per Hedbor  THREADS_DISALLOW(); }
bb66712002-07-04Per Hedbor  else if( t->file_obj )
d7de8f2002-05-29Per Hedbor  { push_string( make_shared_binary_string( t->leftovers.data+t->leftovers.off,
df3d032002-07-04Per Hedbor  MINIMUM(amount,t->leftovers.len) ) );
d7de8f2002-05-29Per Hedbor  apply( t->file_obj, "write", 1 );
017b572011-10-28Henrik Grubbström (Grubba)  if( TYPEOF(Pike_sp[-1]) == PIKE_T_INT )
74bd242002-07-03Per Hedbor  sent = Pike_sp[-1].u.integer;
bb66712002-07-04Per Hedbor  else {
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG2("Oops: write returned object of type %d, not integer\n",
017b572011-10-28Henrik Grubbström (Grubba)  t, TYPEOF(Pike_sp[-1]) );
bb66712002-07-04Per Hedbor  }
d7de8f2002-05-29Per Hedbor  pop_stack(); }
332f4e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG3("__send_more_callback(): sending(%d): sent %d\n", t,
74bd242002-07-03Per Hedbor  MINIMUM(t->leftovers.len,amount),sent );
dd3c382002-05-29Per Hedbor  if( sent < 0 ) { _give_back( t, amount );
08143a2002-11-04Marcus Agehall  _all_done( t, 1 );
dd3c382002-05-29Per Hedbor  return; }
74bd242002-07-03Per Hedbor  if( sent )
dd3c382002-05-29Per Hedbor  {
74bd242002-07-03Per Hedbor  t->sent += sent; if( t->leftovers.len == sent ) { t->leftovers.len = 0; if( t->leftovers.do_free )
dd196c2007-03-06H. William Welliver III  {
74bd242002-07-03Per Hedbor  free( t->leftovers.data );
fc5b3f2007-11-10Martin Nilsson  t->leftovers.data = NULL; t->leftovers.do_free = 0;
dd196c2007-03-06H. William Welliver III  }
74bd242002-07-03Per Hedbor  } else { t->leftovers.len -= sent; t->leftovers.off += sent; }
dd3c382002-05-29Per Hedbor  } if( sent < amount ) _give_back( t, amount-sent ); }
2e1e0b2004-04-04Martin Nilsson  /*! @decl void send_more_callback( int amount ) */
dd3c382002-05-29Per Hedbor  PIKEFUN void send_more_callback( int amount )
2e1e0b2004-04-04Martin Nilsson  optflags OPT_SIDE_EFFECT;
dd3c382002-05-29Per Hedbor  {
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG2("send_more_callback(%d)\n", THIS,amount );
dd3c382002-05-29Per Hedbor  if( THIS->state == RUNNING ) {
d7de8f2002-05-29Per Hedbor  __set_callbacks( THIS );
dd3c382002-05-29Per Hedbor  __send_more_callback( THIS, amount ); } else _give_back( THIS, amount ); }
80439d2004-06-29Stephen R. van den Berg  /*! @decl void write_callback( mixed|void x ) */ PIKEFUN void write_callback( mixed|void x ) optflags OPT_SIDE_EFFECT; { SHUFFLE_DEBUG1("write_callback()\n", THIS ); _send_more( THIS ); }
2e1e0b2004-04-04Martin Nilsson  /*! @decl void create(object fd, object shuffler, mixed throttler,@ *! mixed backend) */
dd3c382002-05-29Per Hedbor  PIKEFUN void create( object fd, object shuffler, mixed throttler, mixed backend )
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
dd3c382002-05-29Per Hedbor  {
0d2d712010-11-03Henrik Grubbström (Grubba)  struct Backend_struct *be = default_backend;
85c1122004-06-27Stephen R. van den Berg 
dd3c382002-05-29Per Hedbor  if( (args != 4) || !shuffler || !get_storage( shuffler, Shuffler_program ) ) Pike_error("This class cannot be instantiated directly\n");
bb66712002-07-04Per Hedbor  THIS->file_obj = fd;
50ea682003-03-14Henrik Grubbström (Grubba)  add_ref(THIS->file_obj);
dd3c382002-05-29Per Hedbor  THIS->shuffler = shuffler;
50ea682003-03-14Henrik Grubbström (Grubba)  add_ref(THIS->shuffler);
dd3c382002-05-29Per Hedbor 
017b572011-10-28Henrik Grubbström (Grubba)  if( TYPEOF(*throttler) == PIKE_T_OBJECT )
dd3c382002-05-29Per Hedbor  { THIS->throttler = throttler->u.object;
50ea682003-03-14Henrik Grubbström (Grubba)  add_ref(THIS->throttler);
dd3c382002-05-29Per Hedbor  }
4945cb2004-07-02Stephen R. van den Berg  if (find_identifier("release_fd", fd->prog) < 0)
85c1122004-06-27Stephen R. van den Berg  change_fd_for_box(&THIS->box, -1);
2e1e0b2004-04-04Martin Nilsson  else {
4945cb2004-07-02Stephen R. van den Berg  safe_apply( fd, "release_fd", 0 );
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(*backend) == PIKE_T_OBJECT && backend->u.object) {
0d2d712010-11-03Henrik Grubbström (Grubba)  be = (struct Backend_struct*) get_storage(backend->u.object, Backend_program); if (!be) { SIMPLE_BAD_ARG_ERROR("Shuffle->create()", 4, "object(Pike.__Backend)"); } }
85c1122004-06-27Stephen R. van den Berg  change_fd_for_box(&THIS->box, Pike_sp[-1].u.integer);
2e1e0b2004-04-04Martin Nilsson  pop_stack(); }
dd3c382002-05-29Per Hedbor 
85c1122004-06-27Stephen R. van den Berg  if( THIS->box.fd >= 0 )
d7de8f2002-05-29Per Hedbor  {
85c1122004-06-27Stephen R. van den Berg  set_nonblocking( THIS->box.fd, 1 );
930bff2010-06-22Henrik Grubbström (Grubba)  if(THIS->box.backend) { /* FIXME: Ought to change backend to be here. */
ca6bd02012-05-01Bill Welliver  set_fd_callback_events(&THIS->box, 0, 0);
930bff2010-06-22Henrik Grubbström (Grubba)  } else
85c1122004-06-27Stephen R. van den Berg  INIT_FD_CALLBACK_BOX(&THIS->box, be, THIS->box.ref_obj,
ca6bd02012-05-01Bill Welliver  THIS->box.fd, 0, got_shuffler_event, 0);
d7de8f2002-05-29Per Hedbor  } else { push_int( 0 ); /* read */ push_int( 0 ); /* write */ push_int( 0 ); /* close */
74bd242002-07-03Per Hedbor  safe_apply( THIS->file_obj, "set_nonblocking", 3 );
d7de8f2002-05-29Per Hedbor  pop_stack(); }
dd3c382002-05-29Per Hedbor  pop_n_elems( args ); push_int(0); } PIKEFUN void start() /*! @decl void start(); *! Start sending data from the sources.
1961162002-06-24Per Hedbor  *!
dd3c382002-05-29Per Hedbor  */
2e1e0b2004-04-04Martin Nilsson  optflags OPT_SIDE_EFFECT;
dd3c382002-05-29Per Hedbor  {
bb66712002-07-04Per Hedbor  if( !THIS->file_obj ) Pike_error("Cannot start, no destination.\n");
dd3c382002-05-29Per Hedbor  THIS->state = RUNNING;
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG1("start()\n", THIS );
dd3c382002-05-29Per Hedbor  _set_callbacks( THIS ); } PIKEFUN void pause() /*! @decl void pause(); *! Temporarily pause all data transmission
1961162002-06-24Per Hedbor  *!
dd3c382002-05-29Per Hedbor  */
2e1e0b2004-04-04Martin Nilsson  optflags OPT_SIDE_EFFECT;
dd3c382002-05-29Per Hedbor  { THIS->state = PAUSED;
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG1("pause()\n", THIS );
dd3c382002-05-29Per Hedbor  _remove_callbacks( THIS ); } PIKEFUN void stop() /*! @decl void stop(); *! Stop all data transmission, and then call the done callback
1961162002-06-24Per Hedbor  *!
dd3c382002-05-29Per Hedbor  */
2e1e0b2004-04-04Martin Nilsson  optflags OPT_SIDE_EFFECT;
dd3c382002-05-29Per Hedbor  {
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG1("stop()\n", THIS );
dd3c382002-05-29Per Hedbor  _all_done( THIS, 2 ); } PIKEFUN void add_source( mixed source, mixed|void start, mixed|void length ) /*! @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.
f2dc812002-11-04Martin Nilsson  *! *! Currently supported sources *! @dl *! @item String *! An ordinary 8-bit wide pike string. *! @item Memory *! An initialized instance of the System.Memory class.
7617622002-11-05Marek Habersack  *! @item NormalFile
f2dc812002-11-04Martin Nilsson  *! Stdio.File instance pointing to a normal file. *! @item 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 *! (set_read_callback and set_close_callback). *! @enddl
dd3c382002-05-29Per Hedbor  */
2e1e0b2004-04-04Martin Nilsson  optflags OPT_SIDE_EFFECT;
dd3c382002-05-29Per Hedbor  { INT64 rstart=0, rlength=-1; struct source *res;
bb66712002-07-04Per Hedbor  if( !THIS->file_obj ) Pike_error("Cannot add source, no destination.\n");
dd3c382002-05-29Per Hedbor  if( args > 1 ) {
017b572011-10-28Henrik Grubbström (Grubba)  if( TYPEOF(*start) == PIKE_T_OBJECT )
dd3c382002-05-29Per Hedbor  int64_from_bignum( &rstart, start->u.object );
0311712013-06-17Martin Nilsson  else if( TYPEOF(*start) == PIKE_T_INT && !SUBTYPEOF(*start) ) rstart = start->u.integer;
dd3c382002-05-29Per Hedbor  } if( args > 2 ) {
017b572011-10-28Henrik Grubbström (Grubba)  if( TYPEOF(*length) == PIKE_T_OBJECT )
74bd242002-07-03Per Hedbor  int64_from_bignum( &rlength, length->u.object );
0311712013-06-17Martin Nilsson  else if( TYPEOF(*length) == PIKE_T_INT && !SUBTYPEOF(*length) ) rlength = length->u.integer;
74bd242002-07-03Per Hedbor  } if( rlength == 0 ) { pop_n_elems(args); push_int(0); return;
dd3c382002-05-29Per Hedbor  }
b2986f2002-07-05Per Hedbor  debug_malloc_touch( source );
dd3c382002-05-29Per Hedbor  res = source_make( source, rstart, rlength );
b2986f2002-07-05Per Hedbor  debug_malloc_touch( res );
dcefdb2004-10-16Henrik Grubbström (Grubba) 
94d29e2002-08-13Henrik Grubbström (Grubba)  SHUFFLE_DEBUG4("add_source(XX,%d,%d) --> %p\n", THIS,
74bd242002-07-03Per Hedbor  (int)rstart, (int)rlength, res );
dd3c382002-05-29Per Hedbor  if( !res ) Pike_error("Failed to convert argument to a source\n");
b685882006-10-31Martin Nilsson  res->next = NULL;
dd3c382002-05-29Per Hedbor  if( THIS->current_source ) { THIS->last_source->next = res; THIS->last_source = res; }
bfb68b2004-10-15Martin Nilsson  else {
dd3c382002-05-29Per Hedbor  THIS->current_source = THIS->last_source = res;
bfb68b2004-10-15Martin Nilsson  }
dd3c382002-05-29Per Hedbor  pop_n_elems(args); push_int(0); } }
1961162002-06-24Per Hedbor 
dd3c382002-05-29Per Hedbor /*! @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 *! or more sources to a destination in the background.
1961162002-06-24Per Hedbor  *!
dd3c382002-05-29Per Hedbor  */ PIKECLASS Shuffler { PIKEVAR object backend; PIKEVAR object throttler; CVAR int paused; PIKEVAR array sources; static void update_sources() { push_array( THIS->sources );
b2986f2002-07-05Per Hedbor  debug_malloc_touch( THIS->sources );
dd3c382002-05-29Per Hedbor  push_int(0); f_aggregate(1); o_subtract(); THIS->sources = Pike_sp[-1].u.array;
b2986f2002-07-05Per Hedbor  debug_malloc_touch( THIS->sources );
dd3c382002-05-29Per Hedbor  Pike_sp--; } PIKEFUN void set_backend( object b )
c018982003-11-16Henrik Grubbström (Grubba)  /*! @decl void set_backend( Pike.Backend b );
dd3c382002-05-29Per Hedbor  *! Set the backend that will be used by all @[Shuffle] objects created *! from this shuffler.
1961162002-06-24Per Hedbor  *!
dd3c382002-05-29Per Hedbor  */ { if( THIS->backend ) free_object( THIS->backend ); THIS->backend = b;
b2986f2002-07-05Per Hedbor  debug_malloc_touch( THIS->backend );
dd3c382002-05-29Per Hedbor  Pike_sp--; push_int(0); }
74bd242002-07-03Per Hedbor  PIKEFUN void set_throttler( object|void t )
dd3c382002-05-29Per Hedbor  /*! @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.
1961162002-06-24Per Hedbor  *!
dd3c382002-05-29Per Hedbor  */ { if( THIS->throttler ) free_object( THIS->throttler );
7ab1f72008-01-21Henrik Grubbström (Grubba)  debug_malloc_pass( THIS->throttler = t );
dd3c382002-05-29Per Hedbor  Pike_sp--; push_int(0); } PIKEFUN void pause() /*! @decl void pause(); *! Pause all @[Shuffle] objects associated with this @[Shuffler]
1961162002-06-24Per Hedbor  *!
dd3c382002-05-29Per Hedbor  */ { int i; update_sources(); for( i = 0; i<THIS->sources->size; i++ ) { struct Shuffle_struct *s = (struct Shuffle_struct *)THIS->sources->item[i].u.object->storage; if( s->state == RUNNING ) _remove_callbacks( s ); } } PIKEFUN void start() /*! @decl void start(); *! Unpause all @[Shuffle] objects associated with this @[Shuffler]
1961162002-06-24Per Hedbor  *!
dd3c382002-05-29Per Hedbor  */ { int i; update_sources(); for( i = 0; i<THIS->sources->size; i++ ) { struct Shuffle_struct *s = (struct Shuffle_struct *)THIS->sources->item[i].u.object->storage; if( s->state == RUNNING ) _set_callbacks( s ); } } PIKEFUN void ___remove_shuffle( object so ) { f_aggregate(1); push_array( THIS->sources ); stack_swap(); o_subtract(); THIS->sources = Pike_sp[-1].u.array;
b2986f2002-07-05Per Hedbor  debug_malloc_touch( THIS->sources );
dd3c382002-05-29Per Hedbor  Pike_sp--; push_int(0); } PIKEFUN object shuffle( object destination ) /*! @decl Shuffle shuffle( Stdio.File destination );
1961162002-06-24Per Hedbor  *! Create a new @[Shuffle] object. *!
dd3c382002-05-29Per Hedbor  */ { 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 push_int( 0 );
bb66712002-07-04Per Hedbor  push_object( clone_object( Shuffle_program, 4 ) );
dd3c382002-05-29Per Hedbor  stack_dup(); f_aggregate( 1 ); push_array( THIS->sources ); stack_swap(); f_add(2); THIS->sources = Pike_sp[-1].u.array;
b2986f2002-07-05Per Hedbor  debug_malloc_touch( THIS->sources );
dd3c382002-05-29Per Hedbor  Pike_sp--; } INIT { THIS->sources = allocate_array(0); } } /*! @endclass */
b0430a2002-11-26Henrik Grubbström (Grubba) /*! @decl constant INITIAL;
1961162002-06-24Per Hedbor  *! @decl constant RUNNING; *! @decl constant PAUSED; *! @decl constant DONE; *! @decl constant WRITE_ERROR; *! @decl constant READ_ERROR; *! @decl constant USER_ABORT; */ /*! @endmodule */
51ef5c2002-10-21Marcus Comstedt PIKE_MODULE_INIT
dd3c382002-05-29Per Hedbor { INIT; sources_init(); add_integer_constant( "INITIAL", INITIAL, 0 ); add_integer_constant( "RUNNING", RUNNING, 0 ); add_integer_constant( "PAUSED", PAUSED, 0 ); add_integer_constant( "DONE", DONE, 0 ); add_integer_constant( "WRITE_ERROR", WRITE_ERROR, 0 ); add_integer_constant( "READ_ERROR", READ_ERROR, 0 ); add_integer_constant( "USER_ABORT", USER_ABORT, 0 ); }
51ef5c2002-10-21Marcus Comstedt PIKE_MODULE_EXIT
dd3c382002-05-29Per Hedbor { EXIT; sources_exit(); }