/* 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); }
static void func_callback_wrapper(int which, sqlite3_context * ctx, int num_args, sqlite3_value ** values) { CB_Data * cb_data = sqlite3_user_data(ctx); DB * db = cb_data->db; lua_State * L = db->L; switch(which) { case 0: push_callback(L, db, KEY_XFUNC(cb_data)); break; case 1: push_callback(L, db, KEY_XSTEP(cb_data)); break; case 2: push_callback(L, db, KEY_XFINAL(cb_data)); break; } if (lua_isnil(L, -1)) { lua_pop(L, 1); fprintf(stderr, "libluasqlite3: func_callback_wrapper: Warning: function is null\n"); return; } lua_pushlightuserdata(L, ctx); if (values) { lua_pushnumber(L, num_args); lua_pushlightuserdata(L, values); } if (lua_pcall(L, values ? 3 : 1, 0, 0)) { fprintf(stderr, "libluasqlite3: func_callback_wrapper: Warning: user function error: %s\n", lua_tostring(L, -1)); sqlite3_result_error(ctx, lua_tostring(L, -1), lua_strlen(L, -1)); lua_pop(L, 1); } }
/* 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); }
/** * \brief Executes the callback of a timer. * * Then, if the callback returns \c true, the timer is rescheduled, * otherwise it is discarded. * * Does nothing if the timer is already finished. * * \param timer The timer to execute. */ void LuaContext::do_timer_callback(Timer& timer) { Debug::check_assertion(timer.is_finished(), "This timer is still running"); const std::map<Timer*, LuaTimerData>::iterator it = timers.find(&timer); if (it != timers.end() && it->second.callback_ref != LUA_REFNIL) { const int callback_ref = it->second.callback_ref; push_callback(callback_ref); const bool success = call_function(0, 1, "timer callback"); bool repeat = false; if (success) { repeat = lua_isboolean(l, -1) && lua_toboolean(l, -1); lua_pop(l, 1); } if (repeat) { // The callback returned true: reschedule the timer. timer.set_expiration_date(timer.get_expiration_date() + timer.get_initial_duration()); if (timer.is_finished()) { // Already finished: this is possible if the duration is smaller than // the main loop stepsize. do_timer_callback(timer); } } else { cancel_callback(callback_ref); it->second.callback_ref = LUA_REFNIL; timers_to_remove.push_back(&timer); } } }
static void tcp_after_close(uv_handle_t* handle) { UNWRAP(handle); lev_handle_unref(L, (LevRefStruct_t*)self); if (push_callback(L, self, "on_close")) { lua_call(L, 1, 0);/*, -3*/ } }
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); }
static void on_connection(uv_stream_t* handle, int status) { UNWRAP(handle); puts(__func__); push_callback(L, self, "on_connection"); lua_pushinteger(L, status); lua_pcall(L, 2, 0, -4); }
int xauth_callback_wrapper(void * cb_data, int auth_request, const char * name1, const char * name2, const char * db_name, const char * trigger_name) { DB * db = CB_DATA(cb_data)->db; lua_State * L = db->L; int result; push_callback(L, db, KEY_XAUTH(cb_data)); lua_pushnumber(L, auth_request); push_nil_or_string(L, name1); push_nil_or_string(L, name2); push_nil_or_string(L, db_name); push_nil_or_string(L, trigger_name); if ( lua_pcall(L, 5, 1, 0) ) { lua_pop(L, 1); return SQLITE_DENY; /* On errors, sqlite should deny access */ } if (lua_isnumber(L, -1)) result = lua_tonumber(L, -1); else result = SQLITE_DENY; /* Wrong result values should deny access */ lua_pop(L, 1); return result; }
enum encoder_action poll_encoder(void) { // Poll switch if (!gpio_get(*inputSwitch) && push_callback != NULL) { // De-bounce _delay_ms( 25 ); while (!gpio_get(*inputSwitch)); push_callback(); return ENCODER_ACTION_PUSH; } // Abort if the position is unchanged if (state.inputA == gpio_get(*inputA) && state.inputB == gpio_get(*inputB)) { return ENCODER_ACTION_NONE; } enum encoder_action action = ENCODER_ACTION_NONE; // Direction: clockwise if ( (!state.inputA && !state.inputB && !gpio_get(*inputA) && gpio_get(*inputB)) || (!state.inputA && state.inputB && gpio_get(*inputA) && gpio_get(*inputA)) || ( state.inputA && state.inputB && !gpio_get(*inputA) && !gpio_get(*inputB)) ) { action = ENCODER_ACTION_CW; ++state.counter; } // Direction: counter-clockwise else if ( ( state.inputA && state.inputB && !gpio_get(*inputA) && gpio_get(*inputB)) || (!state.inputA && state.inputB && !gpio_get(*inputA) && !gpio_get(*inputB)) || (!state.inputA && !state.inputB && gpio_get(*inputA) && gpio_get(*inputB)) ) { action = ENCODER_ACTION_CCW; --state.counter; } // Update input state variables state.inputA = gpio_get(*inputA); state.inputB = gpio_get(*inputB); // On reception of the third pulse in the same direction if (state.counter <= -3 || state.counter >= 3) { // Reset counter state.counter = 0; // Call back if (action == ENCODER_ACTION_CW && cw_callback != NULL) { cw_callback(); } else if (action == ENCODER_ACTION_CCW && ccw_callback != NULL) { ccw_callback(); } return action; } return ENCODER_ACTION_NONE; }
/** * @brief Calls a function stored in the registry with a reference and * releases this reference. * @param callback_ref Reference of the function to call (if LUA_REFNIL, * nothing is done). */ void LuaContext::do_callback(int callback_ref) { if (callback_ref != LUA_REFNIL) { push_callback(callback_ref); call_function(0, 0, "callback"); destroy_ref(callback_ref); } }
/* 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(); }
static void on_connection(uv_stream_t* handle, int status) { UNWRAP(handle); push_callback(L, self, "on_connection"); if (!status) { lua_pushnil(L); } else { lua_pushinteger(L, status); } lua_call(L, 2, 0);/*, -4*/ }
static void xtrace_callback_wrapper(void * cb_data, const char * str) { DB * db = CB_DATA(cb_data)->db; lua_State * L = db->L; push_callback(L, db, KEY_XTRACE(cb_data)); lua_pushstring(L, str); if ( lua_pcall(L, 1, 0, 0) ) lua_pop(L, 1); /* pop error message and delete it (errors are ignored) */ }
void xneeded_callback_wrapper(void * cb_data, sqlite3 * sqlite3, int eTextRep, const char * collation_name) { DB * db = CB_DATA(cb_data)->db; lua_State * L = db->L; push_callback(L, db, KEY_XNEEDED(cb_data)); lua_pushstring(L, collation_name); if (lua_pcall(L, 1, 0, 0)) lua_pop(L, 1); }
static void on_read(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) { UNWRAP(handle); puts(__func__); push_callback(L, self, "on_read"); lua_pushinteger(L, nread); if (nread >= 0) lua_pushlstring(L, buf.base, nread); else lua_pushnil(L); lua_pcall(L, 3, 0, -5); }
static void on_connect(uv_connect_t* req, int status) { UNWRAP(req->handle); push_callback(L, self, "on_connect"); if (!status) { lua_pushnil(L); /*printf("CONNECT ON FD: %d (ref:%d)\n", ( (uv_stream_t*)&self->handle )->fd, ((LevRefStruct_t*)self)->refCount);*/ } else { lua_pushinteger(L, status); lev_handle_unref(L, (LevRefStruct_t*)self); } lua_call(L, 2, 0);/*, -4*/ }
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(); } }
int xcommit_callback_wrapper(void * cb_data) { DB * db = CB_DATA(cb_data)->db; lua_State * L = db->L; push_callback(L, db, KEY_XCOMMIT(cb_data)); if ( lua_pcall(L, 0, 1, 0) ) { lua_pop(L, 1); return 1; /* on errors, rollback */ } return pop_break_condition(L); }
int xbusy_callback_wrapper(void * cb_data, int num_called) { DB * db = CB_DATA(cb_data)->db; lua_State * L = db->L; push_callback(L, db, KEY_XBUSY(cb_data)); lua_pushnumber(L, num_called); if ( lua_pcall(L, 1, 1, 0) ) { lua_pop(L, 1); return 0; /* On errors, sqlite should return SQLITE_BUSY */ } return pop_break_condition(L); /* WARNING: In reality, the semantic is inverted !!!*/ }
int xcompare_callback_wrapper(void * cb_data, int len_a, const void * str_a, int len_b, const void * str_b) { DB * db = CB_DATA(cb_data)->db; lua_State * L = db->L; int result; push_callback(L, db, KEY_XCOMPARE(cb_data)); lua_pushlstring(L, str_a, len_a); lua_pushlstring(L, str_b, len_b); if ( lua_pcall(L, 2, 1, 0) ) result = 0; /* No way to signal errors to sqlite */ else result = (int) lua_tonumber(L, -1); lua_pop(L, 1); return result; }
static void on_close(uv_handle_t* handle) { UNWRAP(handle); push_callback(L, self, "on_close"); lua_pcall(L, 1, 0, -3); }
/* This function reads some data from the file cache.. * Called when we want some data to send. */ static INLINE struct pike_string* gimme_some_data(size_t pos) { struct buffer *b; ptrdiff_t len; struct pipe *this = THIS; /* We have a file cache, read from it */ if (this->fd!=-1) { char buffer[READ_BUFFER_SIZE]; if (this->pos<=pos) return NULL; /* no data */ len=this->pos-pos; if (len>READ_BUFFER_SIZE) len=READ_BUFFER_SIZE; THREADS_ALLOW(); fd_lseek(this->fd, pos, SEEK_SET); THREADS_DISALLOW(); do { THREADS_ALLOW(); len = fd_read(this->fd, buffer, len); THREADS_DISALLOW(); if (len < 0) { if (errno != EINTR) { return(NULL); } check_threads_etc(); } } while(len < 0); /* * FIXME: What if len is 0? */ return make_shared_binary_string(buffer,len); } if (pos<this->pos) return make_shared_string("buffer underflow"); /* shit */ /* We want something in the next buffer */ while (this->firstbuffer && pos>=this->pos+this->firstbuffer->s->len) { /* Free the first buffer, and update THIS->pos */ b=this->firstbuffer; this->pos+=b->s->len; this->bytes_in_buffer-=b->s->len; this->firstbuffer=b->next; if (!b->next) this->lastbuffer=NULL; 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. */ if (this->sleeping && this->firstinput && this->bytes_in_buffer<MAX_BYTES_IN_BUFFER) { if (this->firstinput->type == I_BLOCKING_OBJ) { if (!read_some_data()) { this->sleeping = 0; input_finish(); } } 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(); } } } while (!this->firstbuffer) { if (this->firstinput) { #if defined(HAVE_MMAP) && defined(HAVE_MUNMAP) if (this->firstinput->type==I_MMAP) { char *src; struct pike_string *tmp; if (pos >= this->firstinput->len + this->pos) /* end of mmap */ { this->pos += this->firstinput->len; input_finish(); continue; } len = this->firstinput->len + this->pos - pos; if (len > READ_BUFFER_SIZE) len=READ_BUFFER_SIZE; tmp = begin_shared_string( len ); src = this->firstinput->u.mmap + pos - this->pos; /* This thread_allow/deny is at the cost of one extra memory copy */ THREADS_ALLOW(); MEMCPY(tmp->str, src, len); THREADS_DISALLOW(); return end_shared_string(tmp); } else #endif if (this->firstinput->type!=I_OBJ) { /* FIXME: What about I_BLOCKING_OBJ? */ input_finish(); /* shouldn't be anything else ... maybe a finished object */ } } return NULL; /* no data */ } if (pos==this->pos) { add_ref(this->firstbuffer->s); return this->firstbuffer->s; } return make_shared_binary_string(this->firstbuffer->s->str+ pos-this->pos, this->firstbuffer->s->len- pos+this->pos); }
/*! @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); }
/*! @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); }
void enqueue(const SimpleBuffer &amf, const std::string& identifier, as_object* callback) { push_amf(amf); push_callback(identifier, callback); }
static void on_connect(uv_connect_t* req, int status) { UNWRAP(req->handle); push_callback(L, self, "on_connect"); lua_pushinteger(L, status); lua_pcall(L, 2, 0, -4); }
/* 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(); } }