/* Generated from "/Users/hww3/devel/pike/src/backend.cmod" by precompile.pike running Pike v8.0 release 1091
 *
 * Do NOT edit this file.
 */

#undef PRECOMPILE_API_VERSION
#define PRECOMPILE_API_VERSION 6

#undef PRECOMPILE_SUB_PIKEVARS
#define PRECOMPILE_SUB_PIKEVARS 1

#undef PRECOMPILE_DYNAMIC_TYPES
#define PRECOMPILE_DYNAMIC_TYPES 1



#undef cmod___CMOD__
#define cmod___CMOD__ 1
#line 1 "/Users/hww3/devel/pike/src/backend.cmod"
#line 1 "/Users/hww3/devel/pike/src/backend.cmod"
#line 1 "/Users/hww3/devel/pike/src/backend.cmod"
#line 3003 "/Users/hww3/devel/pike/lib/modules/Tools.pmod/Standalone.pmod/precompile.pike"







#line 3010 "/Users/hww3/devel/pike/lib/modules/Tools.pmod/Standalone.pmod/precompile.pike"
#line 1 "/Users/hww3/devel/pike/src/backend.cmod"
#line 1 "/Users/hww3/devel/pike/src/backend.cmod"
/* -*- 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.
*/

/*
 * Backend object.
 */

#include "global.h"
#include "fdlib.h"
#include "backend.h"
#include "time_stuff.h"
#include <errno.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#include <string.h>
#include "interpret.h"
#include "object.h"
#include "pike_error.h"
#include "fd_control.h"
#include "main.h"
#include "callback.h"
#include "threads.h"
#include "array.h"
#include <math.h>
#include "interpret.h"
#include "stuff.h"
#include "bignum.h"
#include "builtin_functions.h"
#include "mapping.h"
#include "svalue.h"
#include "gc.h"
#include "module_support.h"
#include "block_allocator.h"

/*
 * Things to do
 *
 * o what happens to callbacks on destruct?
 *
 *   They will just cease to generate any events. If the callback
 *   container object uses the old callback interface and has added an
 *   extra ref to itself to account for the callback connection it
 *   will become garbage. The new interface fixes this. /mast
 *
 * o automatic callback assignment based on current thread
 *
 *   Sounds very odd to me. /mast
 */

/* For select */
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#else
/* BeOS socket (select etc) stuff */
#ifdef HAVE_NET_SOCKET_H
#include <net/socket.h>
#endif
#endif
#include <sys/stat.h>

/* For poll and /dev/poll and epoll */
#ifdef HAVE_POLL_H
#include <poll.h>
#endif /* HAVE_POLL_H */
#ifdef HAVE_SYS_POLL_H
#include <sys/poll.h>
#endif /* HAVE_SYS_POLL_H */

/* For /dev/poll */
#ifdef HAVE_SYS_DEVPOLL_H
#include <sys/devpoll.h>
#endif /* HAVE_SYS_DEVPOLL_H */

/* For epoll */
#ifdef HAVE_SYS_EPOLL_H
#include <sys/epoll.h>
#endif /* HAVE_SYS_EPOLL_H */

/* For kqueue. */
#ifdef HAVE_SYS_EVENT_H
#include <sys/event.h>
#endif /* HAVE_SYS_EVENT_H */

/* for kqueue + CFRunLoop */
#ifdef HAVE_CORESERVICES_CORESERVICES_H
#include <CoreServices/CoreServices.h>
#endif /* HAVE_CORESERVICES_CORESERVICES_H */

/* The following are used on Linux'es that have an old libc. */
#ifdef HAVE_SYSCALL_H
#include <syscall.h>
#elif defined(HAVE_SYS_SYSCALL_H)
#include <sys/syscall.h>
#endif /* HAVE_SYSCALL_H || HAVE_SYS_SYSCALL_H */

#if defined(BACKEND_USES_POLL_DEVICE) || defined(BACKEND_USES_KQUEUE)
struct program * PollDeviceBackend_program;
#endif /* BACKEND_USES_POLL_DEVICE || BACKEND_USES_KQUEUE */

/*
 * Debugging and tracing.
 */

/* #define POLL_DEBUG */
/* #define CALL_OUT_DEBUG */

#ifdef PIKE_EXTRA_DEBUG
/* #define POLL_DEBUG */
/* #define CALL_OUT_DEBUG */
#endif

#ifdef POLL_DEBUG
#define IF_PD(x)	x
#define PDUNUSED(x) x
#else /* !POLL_DEBUG */
#define IF_PD(x)
#define PDUNUSED(x) UNUSED(x)
#endif /* POLL_DEBUG */

#ifdef CALL_OUT_DEBUG
#define IF_CO(X) X
#else
#define IF_CO(X)
#endif

#ifdef PIKE_THREADS
#define THR_NO (int) PTR_TO_INT (THREAD_T_TO_PTR (th_self()))
#else
#define THR_NO getpid()
#endif

/* Declarations for the legacy backend interface stuff. */

static struct compat_cb_box * alloc_compat_cb_box(void);
static void really_free_compat_cb_box(struct compat_cb_box * b);
static int compat_box_dispatcher (struct fd_callback_box *box, int event);

#ifdef BACKEND_USES_CFRUNLOOP
/* Used by CoreFoundation backend to get around lack of PDB structures
 * early in the CMOD.
 */
static void check_set_timer(struct timeval when);
#endif
/* CALL OUT STUFF */

#define EXIT_CO(X) do {						\
    if(X->prev_arr) *(X->prev_arr) = X->next_arr;		\
    if(X->next_arr) X->next_arr->prev_arr = X->prev_arr;	\
    if(X->prev_fun) *(X->prev_fun) = X->next_fun;		\
    if(X->next_fun) X->next_fun->prev_fun = X->prev_fun;	\
    (X)->next_arr = NULL;					\
    (X)->next_fun = NULL;					\
    (X)->prev_arr = NULL;					\
    (X)->prev_fun = NULL;					\
  } while(0)

struct hash_ent
{
struct Backend_CallOut_struct *arr;
struct Backend_CallOut_struct *fun;
};



#define DEFAULT_CMOD_STORAGE



#ifndef PIKE_UNUSED_ATTRIBUTE
#define PIKE_UNUSED_ATTRIBUTE
#endif
#define CMOD_MAP_PROGRAM_IDS_DEFINED 1
static int ___cmod_map_program_ids(int id) PIKE_UNUSED_ATTRIBUTE;
#ifndef TYPEOF
/* Compat with older Pikes. */
#define TYPEOF(SVAL)	((SVAL).type)
#define SUBTYPEOF(SVAL)	((SVAL).subtype)
#define SET_SVAL_TYPE(SVAL, TYPE)	(TYPEOF(SVAL) = TYPE)
#define SET_SVAL_SUBTYPE(SVAL, TYPE)	(SUBTYPEOF(SVAL) = TYPE)
#define SET_SVAL(SVAL, TYPE, SUBTYPE, FIELD, EXPR) do {	\
    /* Set the type afterwards to avoid a clobbered	\
     * svalue in case EXPR throws. */			\
    (SVAL).u.FIELD = (EXPR);				\
    SET_SVAL_TYPE((SVAL), (TYPE));			\
    SET_SVAL_SUBTYPE((SVAL), (SUBTYPE));		\
  } while(0)
#endif /* !TYPEOF */
#ifndef PIKE_UNUSED
/* Compat with Pike 7.8 and earlier. */
/* NB: Not strictly correct; PIKE_UNUSED was added the
 *     day after set_program_id_to_id(), but good enough.
 */
#ifndef UNUSED
#define UNUSED(X)	X
#endif
#ifndef set_program_id_to_id
/* NB: Recent Pike 7.8 has a #define that conflicts with
 *     the following declaration.
 */
static void set_program_id_to_id(void*UNUSED(id)){}
#endif
#else /* */
PMOD_EXPORT void set_program_id_to_id( int (*to)(int) );
#endif /* !PIKE_UNUSED */


#ifndef DEFAULT_CMOD_STORAGE
#define CMOD_COND_USED
#define DEFAULT_CMOD_STORAGE static
#endif
#define module_strings_declared
static struct pike_string *module_strings[1] = {
  NULL,
};
static struct { INT32 from;INT32 to; } ___cmod_ext_used[1];
#ifndef CMOD_COND_USED
# define Backend_CallOut_program_fun_num_used 1
#else
#define Backend_CallOut_program_fun_num_used 1
#endif
#ifndef CMOD_COND_USED
# define f_Backend_get_stats_fun_num_used 1
#else
#undef f_Backend_get_stats_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_Backend_call_out_fun_num_used 1
#else
#undef f_Backend_call_out_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_Backend_find_call_out_fun_num_used 1
#else
#undef f_Backend_find_call_out_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_Backend_call_out_info_fun_num_used 1
#else
#undef f_Backend_call_out_info_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_Backend_add_file_fun_num_used 1
#else
#undef f_Backend_add_file_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_Backend_id_fun_num_used 1
#else
#undef f_Backend_id_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_Backend_cq__sprintf_fun_num_used 1
#else
#undef f_Backend_cq__sprintf_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_Backend_create_fun_num_used 1
#else
#undef f_Backend_create_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define Backend_program_fun_num_used 1
#else
#undef Backend_program_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define PollBackend_program_fun_num_used 1
#else
#undef PollBackend_program_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define SelectBackend_program_fun_num_used 1
#else
#undef SelectBackend_program_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_PollBackend_cq__backtick_28_29_fun_num_used 1
#else
#undef f_PollBackend_cq__backtick_28_29_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_Backend_CallOut_create_fun_num_used 1
#else
#undef f_Backend_CallOut_create_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_SelectBackend_cq__backtick_28_29_fun_num_used 1
#else
#undef f_SelectBackend_cq__backtick_28_29_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_Backend_executing_thread_fun_num_used 1
#else
#undef f_Backend_executing_thread_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_Backend_cq__do_call_outs_fun_num_used 1
#else
#undef f_Backend_cq__do_call_outs_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define PollDeviceBackend_program_fun_num_used 1
#else
#undef PollDeviceBackend_program_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_Backend_cq__backtick_28_29_fun_num_used 1
#else
#undef f_Backend_cq__backtick_28_29_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_PollDeviceBackend_query_core_foundation_enabled_fun_num_used 1
#else
#undef f_PollDeviceBackend_query_core_foundation_enabled_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_PollDeviceBackend_enable_core_foundation_fun_num_used 1
#else
#undef f_PollDeviceBackend_enable_core_foundation_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_PollDeviceBackend_cq__backtick_28_29_fun_num_used 1
#else
#undef f_PollDeviceBackend_cq__backtick_28_29_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_Backend_remove_call_out_fun_num_used 1
#else
#undef f_Backend_remove_call_out_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_PollDeviceBackend_set_signal_event_callback_fun_num_used 1
#else
#undef f_PollDeviceBackend_set_signal_event_callback_fun_num_used
#endif
#ifndef CMOD_COND_USED
# define f_PollDeviceBackend_enable_external_runloop_fun_num_used 1
#else
#undef f_PollDeviceBackend_enable_external_runloop_fun_num_used
#endif
#line 177 "/Users/hww3/devel/pike/src/backend.cmod"
struct callback_list do_debug_callbacks;
struct timeval current_time;
int current_time_invalid = 1;

/*
 * Stuff to map fds to the proper Backend
 */
static struct Backend_struct **fd_map=0;
static int fd_map_size=0;
static struct object *default_backend_obj = NULL;

/**
 * The default backend object.
 */
PMOD_EXPORT struct Backend_struct *default_backend = NULL;

#ifdef DO_PIKE_CLEANUP
static int num_active_backends = 0;
#endif

#if defined(BACKEND_USES_CFRUNLOOP)
static void noteEvents(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes,
void *info);
void cfObserverCallback(CFRunLoopObserverRef observer,
CFRunLoopActivity activity, void* info);
void cfTimerCallback(CFRunLoopTimerRef timer, void * info);

#endif /* BACKEND_USES_CFRUNLOOP */

static int backend_do_call_outs(struct Backend_struct *me);
#ifdef PIKE_DEBUG
static void backend_verify_call_outs(struct Backend_struct *me);
#endif
#ifdef DO_PIKE_CLEANUP
static void backend_cleanup(void);
#endif

struct Backend_struct *get_backend_for_fd(int fd)
{
if(fd<0 || fd>=fd_map_size) return 0;
return fd_map[fd];
}

static void low_set_backend_for_fd(int fd, struct Backend_struct *b)
{
#ifdef PIKE_DEBUG
 if(fd<0) Pike_fatal("set_backend_for(%d)\n",fd);
#endif
 if (!b) {
/* Unregister the fd. */
if (fd < fd_map_size) {
fd_map[fd] = NULL;
}
return;
}
if(fd >= fd_map_size)
{
int old=fd_map_size;
if(!fd_map_size) fd_map_size=64;
while(fd >= fd_map_size) fd_map_size*=2;
if (fd_map) {
fd_map = realloc(fd_map, sizeof(struct Backend_struct *) * fd_map_size);
} else {
fd_map = calloc(sizeof(struct Backend_struct *), fd_map_size);
}
if(!fd_map)
Pike_fatal("Out of memory in backend:low_set_backend_for_fd.\n"
"Tried to allocate %"PRINTSIZET"d bytes.\n",
sizeof(struct Backend_struct *) * fd_map_size);

memset(fd_map+old,0,sizeof(struct Backend_struct *) * (fd_map_size-old));
}
fd_map[fd]=b;
}

struct Backend_struct *really_get_backend_for_fd(int fd)
{
struct Backend_struct *b;
if((b=get_backend_for_fd(fd)))
return b;

#ifdef PIKE_DEBUG
 if(!default_backend)
Pike_fatal("No backend!\n");
#endif
 low_set_backend_for_fd(fd, default_backend);
return default_backend;
}

/*! @module Pike
 */

/*! @class __Backend
 *!   Base class for the various backend implementations.
 *!
 *!   Implements callback registration functions and defines the
 *!   main backend APIs.
 */

#undef class_Backend_defined
#define class_Backend_defined
DEFAULT_CMOD_STORAGE struct program *Backend_program=NULL;

#ifdef Backend_program_fun_num_used
DEFAULT_CMOD_STORAGE int Backend_program_fun_num=-1;
#endif /* Backend_program_fun_num_used */
#line 277 "/Users/hww3/devel/pike/src/backend.cmod"
/* Provide a unique count to be able to tell backends apart with _sprintf. */
static int unused_id = 0;

#undef var_id_Backend_defined
#define var_id_Backend_defined

#undef var_next_timeout_Backend_defined
#define var_next_timeout_Backend_defined
#line 283 "/Users/hww3/devel/pike/src/backend.cmod"
/*
   * Backend callbacks
   */

#undef var_backend_callbacks_Backend_defined
#define var_backend_callbacks_Backend_defined
/*! @decl function(Backend:void) before_callback
   *! @decl function(Backend:void) after_callback
   *!
   *! If set, these are called just before and after the backend waits
   *! for an event.
   *!
   *! If an error is thrown from these callbacks then it is reported
   *! using @expr{master()->handle_error()@} - it doesn't interrupt
   *! the operation of the backend.
   */
#line 298 "/Users/hww3/devel/pike/src/backend.cmod"
/* before_callback is not strictly necessary since one can just as
   * well run it before `(), but it's convenient to have a standard
   * place to hook in a function. */

#undef var_before_callback_Backend_defined
#define var_before_callback_Backend_defined

#undef var_after_callback_Backend_defined
#define var_after_callback_Backend_defined
#line 304 "/Users/hww3/devel/pike/src/backend.cmod"
#ifdef PIKE_THREADS
 /* Thread currently executing in the backend. */

#undef var_exec_thread_Backend_defined
#define var_exec_thread_Backend_defined
#line 308 "/Users/hww3/devel/pike/src/backend.cmod"
/* Signal to wake up other threads waiting on the backend. */

#undef var_backend_signal_Backend_defined
#define var_backend_signal_Backend_defined
#line 311 "/Users/hww3/devel/pike/src/backend.cmod"
/* Incremented when a backend round has called any callbacks. */

#undef var_done_counter_Backend_defined
#define var_done_counter_Backend_defined
#line 313 "/Users/hww3/devel/pike/src/backend.cmod"
#else
 
#undef var_exec_thread_Backend_defined_2
#define var_exec_thread_Backend_defined_2
#line 314 "/Users/hww3/devel/pike/src/backend.cmod"
/* 1 if inside the backend. */
#endif

/*
   * PIPE for waking up
   */

#undef var_wakeup_pipe_send_fd_Backend_defined
#define var_wakeup_pipe_send_fd_Backend_defined

#undef var_wakeup_cb_box_Backend_defined
#define var_wakeup_cb_box_Backend_defined

#undef var_may_need_wakeup_Backend_defined
#define var_may_need_wakeup_Backend_defined
#line 324 "/Users/hww3/devel/pike/src/backend.cmod"
/*
   * FD callback data
   */

/* An array indexed on fd with arbitrary upper and lower bounds. A
   * lower bound is used to cut down the size for backends that
   * handle a single or only a few fd's. */

#undef var_fd_boxes_Backend_defined
#define var_fd_boxes_Backend_defined

#undef var_fd_boxes_size_Backend_defined
#define var_fd_boxes_size_Backend_defined
#line 334 "/Users/hww3/devel/pike/src/backend.cmod"
/* Callback boxes which don't correspond to any open file. */

#undef var_free_inactive_box_Backend_defined
#define var_free_inactive_box_Backend_defined

#undef var_inactive_boxes_size_Backend_defined
#define var_inactive_boxes_size_Backend_defined
#line 338 "/Users/hww3/devel/pike/src/backend.cmod"
/*
   * Hooks to inheriting classes.
   */
#ifdef PIKE_DEBUG
 typedef void debug_handler_fn (struct Backend_struct *me, void *data);

#undef var_debug_handler_Backend_defined
#define var_debug_handler_Backend_defined
#line 344 "/Users/hww3/devel/pike/src/backend.cmod"
#endif /* PIKE_DEBUG */
 typedef void update_fd_set_handler_fn (struct Backend_struct *me, void *data,
int fd,
int old_events, int new_events,
int flags);

#undef var_update_fd_set_handler_Backend_defined
#define var_update_fd_set_handler_Backend_defined

#undef var_handler_data_Backend_defined
#define var_handler_data_Backend_defined
#line 352 "/Users/hww3/devel/pike/src/backend.cmod"
/*
   * CALL OUT variables
   */

#undef var_num_pending_calls_Backend_defined
#define var_num_pending_calls_Backend_defined
#line 355 "/Users/hww3/devel/pike/src/backend.cmod"
/* no of busy pointers in heap */

#undef var_call_heap_Backend_defined
#define var_call_heap_Backend_defined
#line 356 "/Users/hww3/devel/pike/src/backend.cmod"
/* pointer to heap */

#undef var_call_heap_size_Backend_defined
#define var_call_heap_size_Backend_defined
#line 357 "/Users/hww3/devel/pike/src/backend.cmod"
/* no of pointers in heap */


#undef var_hash_size_Backend_defined
#define var_hash_size_Backend_defined

#undef var_hash_order_Backend_defined
#define var_hash_order_Backend_defined

#undef var_call_hash_Backend_defined
#define var_call_hash_Backend_defined
#line 363 "/Users/hww3/devel/pike/src/backend.cmod"
/* Should really exist only in PIKE_DEBUG, but 
   * #ifdefs on the last cvar confuses precompile.pike.
   *	/grubba 2001-03-12
   * Should be fixed now -Hubbe
   */
#ifdef PIKE_DEBUG
 
#undef var_inside_call_out_Backend_defined
#define var_inside_call_out_Backend_defined
#line 370 "/Users/hww3/devel/pike/src/backend.cmod"
#endif

/* The object we're in. This ref isn't refcounted. */

#undef var_backend_obj_Backend_defined
#define var_backend_obj_Backend_defined
#line 375 "/Users/hww3/devel/pike/src/backend.cmod"
#ifdef _REENTRANT
 /* Currently only used for poll devices. */

#undef var_set_busy_Backend_defined
#define var_set_busy_Backend_defined

#undef var_set_change_Backend_defined
#define var_set_change_Backend_defined
#line 379 "/Users/hww3/devel/pike/src/backend.cmod"
#endif


#undef THIS
#define THIS ((struct Backend_struct *)(Pike_interpreter.frame_pointer->current_storage))

#undef THIS_BACKEND
#define THIS_BACKEND ((struct Backend_struct *)(Pike_interpreter.frame_pointer->current_storage))

#undef OBJ2_BACKEND
#define OBJ2_BACKEND(o) ((struct Backend_struct *)(o->storage+Backend_storage_offset))

#undef GET_BACKEND_STORAGE
#define GET_BACKEND_STORAGE(o) ((struct Backend_struct *)(o->storage+Backend_storage_offset)
static ptrdiff_t Backend_storage_offset;
struct Backend_struct {

#ifdef var_id_Backend_defined
#line 279 "/Users/hww3/devel/pike/src/backend.cmod"
int id;
#endif /* var_id_Backend_defined */

#ifdef var_next_timeout_Backend_defined
#line 281 "/Users/hww3/devel/pike/src/backend.cmod"
struct timeval next_timeout;
#endif /* var_next_timeout_Backend_defined */

#ifdef var_backend_callbacks_Backend_defined
#line 286 "/Users/hww3/devel/pike/src/backend.cmod"
struct callback_list backend_callbacks;
#endif /* var_backend_callbacks_Backend_defined */

#ifdef var_before_callback_Backend_defined
  struct svalue before_callback;

#endif /* var_before_callback_Backend_defined */

#ifdef var_after_callback_Backend_defined
  struct svalue after_callback;

#endif /* var_after_callback_Backend_defined */

#ifdef var_exec_thread_Backend_defined
#line 306 "/Users/hww3/devel/pike/src/backend.cmod"
struct thread_state *exec_thread;
#endif /* var_exec_thread_Backend_defined */

#ifdef var_backend_signal_Backend_defined
#line 309 "/Users/hww3/devel/pike/src/backend.cmod"
COND_T backend_signal;
#endif /* var_backend_signal_Backend_defined */

#ifdef var_done_counter_Backend_defined
#line 312 "/Users/hww3/devel/pike/src/backend.cmod"
int done_counter;
#endif /* var_done_counter_Backend_defined */

#ifdef var_exec_thread_Backend_defined_2
#line 314 "/Users/hww3/devel/pike/src/backend.cmod"
int exec_thread;
#endif /* var_exec_thread_Backend_defined_2 */

#ifdef var_wakeup_pipe_send_fd_Backend_defined
#line 320 "/Users/hww3/devel/pike/src/backend.cmod"
int wakeup_pipe_send_fd;
#endif /* var_wakeup_pipe_send_fd_Backend_defined */

#ifdef var_wakeup_cb_box_Backend_defined
#line 321 "/Users/hww3/devel/pike/src/backend.cmod"
struct fd_callback_box wakeup_cb_box;
#endif /* var_wakeup_cb_box_Backend_defined */

#ifdef var_may_need_wakeup_Backend_defined
#line 322 "/Users/hww3/devel/pike/src/backend.cmod"
int may_need_wakeup;
#endif /* var_may_need_wakeup_Backend_defined */

#ifdef var_fd_boxes_Backend_defined
#line 331 "/Users/hww3/devel/pike/src/backend.cmod"
struct fd_callback_box **fd_boxes;
#endif /* var_fd_boxes_Backend_defined */

#ifdef var_fd_boxes_size_Backend_defined
#line 332 "/Users/hww3/devel/pike/src/backend.cmod"
int fd_boxes_start, fd_boxes_size;
#endif /* var_fd_boxes_size_Backend_defined */

#ifdef var_free_inactive_box_Backend_defined
#line 335 "/Users/hww3/devel/pike/src/backend.cmod"
struct fd_callback_box **inactive_boxes, **free_inactive_box;
#endif /* var_free_inactive_box_Backend_defined */

#ifdef var_inactive_boxes_size_Backend_defined
#line 336 "/Users/hww3/devel/pike/src/backend.cmod"
int inactive_boxes_size;
#endif /* var_inactive_boxes_size_Backend_defined */

#ifdef var_debug_handler_Backend_defined
#line 343 "/Users/hww3/devel/pike/src/backend.cmod"
debug_handler_fn *debug_handler;
#endif /* var_debug_handler_Backend_defined */

#ifdef var_update_fd_set_handler_Backend_defined
#line 349 "/Users/hww3/devel/pike/src/backend.cmod"
update_fd_set_handler_fn *update_fd_set_handler;
#endif /* var_update_fd_set_handler_Backend_defined */

#ifdef var_handler_data_Backend_defined
#line 350 "/Users/hww3/devel/pike/src/backend.cmod"
void *handler_data;
#endif /* var_handler_data_Backend_defined */

#ifdef var_num_pending_calls_Backend_defined
#line 355 "/Users/hww3/devel/pike/src/backend.cmod"
int num_pending_calls;
#endif /* var_num_pending_calls_Backend_defined */

#ifdef var_call_heap_Backend_defined
#line 356 "/Users/hww3/devel/pike/src/backend.cmod"
struct Backend_CallOut_struct **call_heap;
#endif /* var_call_heap_Backend_defined */

#ifdef var_call_heap_size_Backend_defined
#line 357 "/Users/hww3/devel/pike/src/backend.cmod"
int call_heap_size;
#endif /* var_call_heap_size_Backend_defined */

#ifdef var_hash_size_Backend_defined
#line 359 "/Users/hww3/devel/pike/src/backend.cmod"
unsigned int hash_size;
#endif /* var_hash_size_Backend_defined */

#ifdef var_hash_order_Backend_defined
#line 360 "/Users/hww3/devel/pike/src/backend.cmod"
unsigned int hash_order;
#endif /* var_hash_order_Backend_defined */

#ifdef var_call_hash_Backend_defined
#line 361 "/Users/hww3/devel/pike/src/backend.cmod"
struct hash_ent *call_hash;
#endif /* var_call_hash_Backend_defined */

#ifdef var_inside_call_out_Backend_defined
#line 369 "/Users/hww3/devel/pike/src/backend.cmod"
int inside_call_out;
#endif /* var_inside_call_out_Backend_defined */

#ifdef var_backend_obj_Backend_defined
struct object *backend_obj;
#endif /* var_backend_obj_Backend_defined */

#ifdef var_set_busy_Backend_defined
int set_busy;
#endif /* var_set_busy_Backend_defined */

#ifdef var_set_change_Backend_defined
#line 378 "/Users/hww3/devel/pike/src/backend.cmod"
COND_T set_change;
#endif /* var_set_change_Backend_defined */
};
#ifdef PIKE_DEBUG
/* Ensure the struct is used in a variable declaration, or else gdb might not see it. */
static struct Backend_struct *Backend_gdb_dummy_ptr;
#endif
#line 383 "/Users/hww3/devel/pike/src/backend.cmod"
/**
   * Get the backend object containing the provided Backend_struct.
   */
PMOD_EXPORT struct object *get_backend_obj (struct Backend_struct *b)
{
return b->backend_obj;
}

static int wakeup_callback(struct fd_callback_box *box, int UNUSED(event))
{
char buffer[1024];
while( (fd_read(box->fd, buffer, sizeof(buffer)) < 0) && (errno==EINTR))
; /* Clear 'flag' */
#ifdef _REENTRANT
 while (box->backend->set_busy) {
co_wait_interpreter(&box->backend->set_change);
}
#endif /* _REENTRANT */
 return 0;
}

/**
   * Wake up the provided backend.
   *
   * This is used by threaded programs and signals to wake up the
   * master 'thread'.
   *
   * It's called from the signal handler so it must not lock any mutex
   * whatsoever. E.g. dmalloc stuff is verboten here.
   */
PMOD_EXPORT void backend_wake_up_backend(struct Backend_struct *me)
{
char foo=0;

if(me && me->may_need_wakeup && (me->wakeup_pipe_send_fd >= 0)) {
/* Avoid fd_write with its dmalloc stuff. */
int len;
do {
len =
#ifdef HAVE_WINSOCK_H
 debug_fd_write
#else
 write
#endif
 (me->wakeup_pipe_send_fd, &foo ,1);
} while ((len < 0) && (errno == EINTR));
}
}

/**
   * Lower the timeout
   *
   * Typically used from backend callbacks.
   */
PMOD_EXPORT void backend_lower_timeout(struct Backend_struct *me,
struct timeval *tv)
{
if (my_timercmp(tv, <=, &me->next_timeout)) {
me->next_timeout = *tv;
}
}

/*
   * Backend callbacks.
   */

PMOD_EXPORT struct callback *backend_debug_add_backend_callback(
struct Backend_struct *me, callback_func call, void *arg,
callback_func free_func)
{
return add_to_callback(& me->backend_callbacks, call, arg, free_func);
}

void call_backend_monitor_cb (struct Backend_struct *me, struct svalue *cb)
{
ref_push_object (me->backend_obj);
safe_apply_svalue (cb, 1, 1);
pop_stack();
}

/*
   * Call outs.
   */

/*! @class CallOut
   *!
   *! Represents a single call_out in the call_out list.
   *!
   *! @seealso
   *!   @[call_out()]
   */

#undef class_Backend_CallOut_defined
#define class_Backend_CallOut_defined
DEFAULT_CMOD_STORAGE struct program *Backend_CallOut_program=NULL;

#ifdef Backend_CallOut_program_fun_num_used
DEFAULT_CMOD_STORAGE int Backend_CallOut_program_fun_num=-1;
#endif /* Backend_CallOut_program_fun_num_used */

#undef var_pos_Backend_CallOut_defined
#define var_pos_Backend_CallOut_defined

#undef var_fun_hval_Backend_CallOut_defined
#define var_fun_hval_Backend_CallOut_defined

#undef var_tv_Backend_CallOut_defined
#define var_tv_Backend_CallOut_defined

#undef var_next_fun_Backend_CallOut_defined
#define var_next_fun_Backend_CallOut_defined

#undef var_prev_fun_Backend_CallOut_defined
#define var_prev_fun_Backend_CallOut_defined

#undef var_next_arr_Backend_CallOut_defined
#define var_next_arr_Backend_CallOut_defined

#undef var_prev_arr_Backend_CallOut_defined
#define var_prev_arr_Backend_CallOut_defined
/*! @decl protected array args
     *!
     *! The array containing the function and arguments.
     */

#undef var_args_Backend_CallOut_defined
#define var_args_Backend_CallOut_defined

#undef var_this_Backend_CallOut_defined
#define var_this_Backend_CallOut_defined

#undef THIS
#define THIS ((struct Backend_CallOut_struct *)(Pike_interpreter.frame_pointer->current_storage))

#undef THIS_BACKEND_CALLOUT
#define THIS_BACKEND_CALLOUT ((struct Backend_CallOut_struct *)(Pike_interpreter.frame_pointer->current_storage))

#undef OBJ2_BACKEND_CALLOUT
#define OBJ2_BACKEND_CALLOUT(o) ((struct Backend_CallOut_struct *)(o->storage+Backend_CallOut_storage_offset))

#undef GET_BACKEND_CALLOUT_STORAGE
#define GET_BACKEND_CALLOUT_STORAGE(o) ((struct Backend_CallOut_struct *)(o->storage+Backend_CallOut_storage_offset)
static ptrdiff_t Backend_CallOut_storage_offset;
struct Backend_CallOut_struct {

#ifdef var_pos_Backend_CallOut_defined
#line 478 "/Users/hww3/devel/pike/src/backend.cmod"
INT32 pos;
#endif /* var_pos_Backend_CallOut_defined */

#ifdef var_fun_hval_Backend_CallOut_defined
#line 479 "/Users/hww3/devel/pike/src/backend.cmod"
size_t fun_hval;
#endif /* var_fun_hval_Backend_CallOut_defined */

#ifdef var_tv_Backend_CallOut_defined
#line 480 "/Users/hww3/devel/pike/src/backend.cmod"
struct timeval tv;
#endif /* var_tv_Backend_CallOut_defined */

#ifdef var_next_fun_Backend_CallOut_defined
#line 481 "/Users/hww3/devel/pike/src/backend.cmod"
struct Backend_CallOut_struct *next_fun;
#endif /* var_next_fun_Backend_CallOut_defined */

#ifdef var_prev_fun_Backend_CallOut_defined
#line 482 "/Users/hww3/devel/pike/src/backend.cmod"
struct Backend_CallOut_struct **prev_fun;
#endif /* var_prev_fun_Backend_CallOut_defined */

#ifdef var_next_arr_Backend_CallOut_defined
#line 483 "/Users/hww3/devel/pike/src/backend.cmod"
struct Backend_CallOut_struct *next_arr;
#endif /* var_next_arr_Backend_CallOut_defined */

#ifdef var_prev_arr_Backend_CallOut_defined
#line 484 "/Users/hww3/devel/pike/src/backend.cmod"
struct Backend_CallOut_struct **prev_arr;
#endif /* var_prev_arr_Backend_CallOut_defined */

#ifdef var_args_Backend_CallOut_defined
  struct array * args;

#endif /* var_args_Backend_CallOut_defined */

#ifdef var_this_Backend_CallOut_defined
#line 491 "/Users/hww3/devel/pike/src/backend.cmod"
struct object *this;
#endif /* var_this_Backend_CallOut_defined */
};
#ifdef PIKE_DEBUG
/* Ensure the struct is used in a variable declaration, or else gdb might not see it. */
static struct Backend_CallOut_struct *Backend_CallOut_gdb_dummy_ptr;
#endif
#line 493 "/Users/hww3/devel/pike/src/backend.cmod"
;

#undef CAR
#undef CDR

#define CAR(X) (((X)<<1)+1)
#define CDR(X) (((X)<<1)+2)
#define PARENT(X) (((X)-1)>>1)
#define CALL_(X) (me->call_heap[(X)])
#define CALL(X) ((struct Backend_CallOut_struct *)debug_malloc_pass(CALL_(X)))
#define MOVECALL(X,Y) do { INT32 p_=(X); (CALL_(p_)=CALL(Y))->pos=p_; }while(0)
#define CMP(X,Y) my_timercmp(& CALL(X)->tv, <, & CALL(Y)->tv)
#define SWAP(X,Y) do {				   \
      struct Backend_CallOut_struct *_tmp=CALL(X); \
      (CALL_(X)=CALL(Y))->pos=(X);		   \
      (CALL_(Y)=_tmp)->pos=(Y);			   \
    } while(0)

#ifdef PIKE_DEBUG
 static void do_unprotect_call_outs(struct Backend_struct *me)
{
me->inside_call_out = 0;
}

#define DECLARE_PROTECT_CALL_OUTS	ONERROR pco_err
#define PROTECT_CALL_OUTS()					\
  do {								\
    if(me->inside_call_out)					\
      Pike_fatal("Recursive call in call_out module.\n");	\
    SET_ONERROR(pco_err, do_unprotect_call_outs, me);		\
    me->inside_call_out=1;					\
  } while(0)
 
#define UNPROTECT_CALL_OUTS()			\
  CALL_AND_UNSET_ONERROR(pco_err)

#else /* !PIKE_DEBUG */
#define DECLARE_PROTECT_CALL_OUTS
#define PROTECT_CALL_OUTS()
#define UNPROTECT_CALL_OUTS()
#endif /* PIKE_DEBUG */

#ifdef PIKE_DEBUG
 
static void backend_verify_call_outs(struct Backend_struct *me)
{
struct array *v;
int e,d;

if(!d_flag) return;
if(!me->call_heap) return;

if(me->num_pending_calls<0 || me->num_pending_calls>me->call_heap_size)
Pike_fatal("Error in call out tables.\n");

if(d_flag<2) return;

for(e=0;e<me->num_pending_calls;e++)
{
if(e)
{
if(CMP(e, PARENT(e)))
Pike_fatal("Error in call out heap. (@ %d)\n",e);
}

if(!(v=CALL(e)->args))
Pike_fatal("No arguments to call.\n");

if(v->refs < 1)
Pike_fatal("Array should have at least one reference.\n");

if(v->malloced_size<v->size)
Pike_fatal("Impossible array.\n");

if(!v->size)
Pike_fatal("Call out array of zero size!\n");

if(CALL(e)->prev_arr[0] != CALL(e))
Pike_fatal("call_out[%d]->prev_arr[0] is wrong!\n",e);

if(CALL(e)->prev_fun[0] != CALL(e))
Pike_fatal("call_out[%d]->prev_fun[0] is wrong!\n",e);

if(CALL(e)->pos != e)
Pike_fatal("Call_out->pos is not correct!\n");

if(d_flag>4)
{
for(d=e+1;d<me->num_pending_calls;d++)
if(CALL(e)->args == CALL(d)->args)
Pike_fatal("Duplicate call out in heap.\n");
}
}

for(d=0;d<10 && e<me->call_heap_size;d++,e++) {
if (CALL(e)) Pike_fatal("Call out left in heap.\n");
}

for(e=0;e<(int)me->hash_size;e++)
{
struct Backend_CallOut_struct *c,**prev;
for(prev=& me->call_hash[e].arr;(c=*prev);prev=& c->next_arr)
{
if(c->prev_arr != prev)
Pike_fatal("c->prev_arr is wrong %p.\n",c);

if(c->pos<0)
Pike_fatal("Free call_out in call_out hash table %p.\n",c);
}

for(prev=& me->call_hash[e].fun;(c=*prev);prev=& c->next_fun)
{
if(c->prev_fun != prev)
Pike_fatal("c->prev_fun is wrong %p.\n",c);

if(c->pos<0)
Pike_fatal("Free call_out in call_out hash table %p.\n",c);
}
}
}


#else
#define backend_verify_call_outs(X)
#endif


static void adjust_down(struct Backend_struct *me,int pos)
{
while(1)
{
int a=CAR(pos), b=CDR(pos);
if(a >= me->num_pending_calls) break;
if(b < me->num_pending_calls)
if(CMP(b, a))
a=b;

if(CMP(pos, a)) break;
SWAP(pos, a);
pos=a;
}
}

static int adjust_up(struct Backend_struct *me,int pos)
{
int parent=PARENT(pos);
int from;
#ifdef PIKE_DEBUG
 if(pos <0 || pos>=me->num_pending_calls)
Pike_fatal("Bad argument to adjust_up(%d)\n",pos);
#endif
 if(!pos) return 0;

if(CMP(pos, parent))
{
SWAP(pos, parent);
from=pos;
pos=parent;
while(pos && CMP(pos, PARENT(pos)))
{
parent=PARENT(pos);
SWAP(pos, parent);
from=pos;
pos=parent;
}
from+=from&1 ? 1 : -1;
if(from < me->num_pending_calls && CMP(from, pos))
{
SWAP(from, pos);
adjust_down(me,from);
}
return 1;
}
return 0;
}

static void adjust(struct Backend_struct *me,int pos)
{
if(!adjust_up(me,pos)) adjust_down(me,pos);
}


#undef internal_init_Backend_CallOut_defined
#define internal_init_Backend_CallOut_defined

#undef Backend_CallOut_event_handler_defined
#define Backend_CallOut_event_handler_defined
static void init_Backend_CallOut_struct(void)
#line 675 "/Users/hww3/devel/pike/src/backend.cmod"
{
THIS->pos = -1;
THIS->this = Pike_fp->current_object;
}


#undef Backend_CallOut_gc_live_obj
#define Backend_CallOut_gc_live_obj

#undef internal_exit_Backend_CallOut_defined
#define internal_exit_Backend_CallOut_defined

#undef Backend_CallOut_event_handler_defined
#define Backend_CallOut_event_handler_defined
static void exit_Backend_CallOut_struct(void)
#line 681 "/Users/hww3/devel/pike/src/backend.cmod"
{
struct Backend_CallOut_struct *this = THIS;

if (this->pos >= 0) {
/* Still active in the heap. DO_PIKE_CLEANUP? */
struct Backend_struct *me = parent_storage(1, Backend_program);
int e = this->pos;

me->num_pending_calls--;
if (e != me->num_pending_calls) {
MOVECALL(e, me->num_pending_calls);
adjust(me, e);
}
CALL_(me->num_pending_calls) = NULL;
this->pos = -1;
free_object(this->this);
this->this = NULL;
}
EXIT_CO(this);
}

/*! @decl void create(int|float seconds, mixed fun, mixed ... args)
     *!
     *!   Start a new call out.
     *!
     *!   This is the low-level implementation of @[call_out()].
     *!
     *!   @[call_out()] is essentially implemented as:
     *!   @code
     *!     array call_out(mixed fun, int|float seconds, mixed ... args)
     *!     {
     *!       return CallOut(seconds, fun, @@args)->args;
     *!     }
     *!   @endcode
     *!
     *! @seealso
     *!   @[call_out()]
     */
#define f_Backend_CallOut_create_defined

#ifdef f_Backend_CallOut_create_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_Backend_CallOut_create_fun_num = 0;

#endif /* f_Backend_CallOut_create_fun_num_used */
DEFAULT_CMOD_STORAGE void f_Backend_CallOut_create(INT32 args) {
#line 719 "/Users/hww3/devel/pike/src/backend.cmod"
struct svalue * seconds;
#line 719 "/Users/hww3/devel/pike/src/backend.cmod"
struct svalue * fun;
#line 719 "/Users/hww3/devel/pike/src/backend.cmod"
struct svalue * extra_args;
#line 719 "/Users/hww3/devel/pike/src/backend.cmod"
if(args < 2) wrong_number_of_args_error("create",args,2);
#line 719 "/Users/hww3/devel/pike/src/backend.cmod"
seconds=Pike_sp+0-args; dmalloc_touch_svalue(Pike_sp+0-args);
#line 719 "/Users/hww3/devel/pike/src/backend.cmod"
fun=Pike_sp+1-args; dmalloc_touch_svalue(Pike_sp+1-args);
#line 719 "/Users/hww3/devel/pike/src/backend.cmod"
if (args > 2) {
  INT32 argcnt = 0;
  do {
    dmalloc_touch_svalue(Pike_sp+2+argcnt-args);
#line 719 "/Users/hww3/devel/pike/src/backend.cmod"
  } while (++argcnt < args-2);
  extra_args=Pike_sp+2-args;
} else extra_args = NULL;
#line 721 "/Users/hww3/devel/pike/src/backend.cmod"
{
struct array *callable;
size_t fun_hval;
size_t hval;
struct Backend_struct *me = parent_storage(1, Backend_program);
struct Backend_CallOut_struct *new = THIS;
DECLARE_PROTECT_CALL_OUTS;

push_array(callable = aggregate_array(args - 1));
args = 2;

/* NOTE: hash_svalue() can run Pike code! */
fun_hval = hash_svalue(ITEM(callable));

PROTECT_CALL_OUTS();
if(me->num_pending_calls == me->call_heap_size)
{
/* here we need to allocate space for more pointers */
struct Backend_CallOut_struct **new_heap;

if(!me->call_heap || !me->call_hash)
{
if (!me->call_heap) {
me->call_heap_size = 128;
me->call_heap = xcalloc(sizeof(struct Backend_CallOut_struct *),
me->call_heap_size);
me->num_pending_calls = 0;
}

if (!me->call_hash) {
me->hash_size = hashprimes[me->hash_order];
me->call_hash = xcalloc(sizeof(struct hash_ent), me->hash_size);
}
}else{
struct hash_ent *new_hash;
int e;

new_heap = realloc(me->call_heap,
sizeof(struct Backend_CallOut_struct *)*me->call_heap_size*2);
if(!new_heap)
Pike_error("Not enough memory for another call_out\n");
memset(new_heap + me->call_heap_size, 0,
sizeof(struct Backend_CallOut_struct *)*me->call_heap_size);
me->call_heap_size *= 2;
me->call_heap = new_heap;

if((new_hash=calloc(sizeof(struct hash_ent),
hashprimes[me->hash_order+1])))
{
free(me->call_hash);
me->call_hash = new_hash;
me->hash_size = hashprimes[++me->hash_order];

/* Re-hash */
for(e=0;e<me->num_pending_calls;e++)
{
struct Backend_CallOut_struct *c = CALL(e);
hval = PTR_TO_INT(c->args);

#define LINK(X,c)							\
	      hval %= me->hash_size;					\
	      if((c->PIKE_CONCAT(next_,X) = me->call_hash[hval].X))	\
		c->PIKE_CONCAT(next_,X)->PIKE_CONCAT(prev_,X) =		\
		  &c->PIKE_CONCAT(next_,X);				\
	      c->PIKE_CONCAT(prev_,X) = &me->call_hash[hval].X;		\
	      me->call_hash[hval].X = c

LINK(arr,c);
hval = c->fun_hval;
LINK(fun,c);
}
}
}
}

#ifdef PIKE_DEBUG
 if (CALL(me->num_pending_calls)) {
Pike_fatal("Lost call out in heap.\n");
}
#endif /* PIKE_DEBUG */

CALL_(me->num_pending_calls) = new;
new->pos = me->num_pending_calls++;
add_ref(Pike_fp->current_object);

{
hval = PTR_TO_INT(callable);
LINK(arr,new);
hval = new->fun_hval = fun_hval;
LINK(fun,new);
}

switch(TYPEOF(*seconds))
{
case T_INT:
new->tv.tv_sec = seconds->u.integer;
new->tv.tv_usec = 0;
break;

case T_FLOAT:
{
FLOAT_TYPE tmp = seconds->u.float_number;
new->tv.tv_sec = DO_NOT_WARN((long)floor(tmp));
new->tv.tv_usec = DO_NOT_WARN((long)(1000000.0 * (tmp - floor(tmp))));
break;
}

default:
Pike_fatal("Bad timeout to new_call_out!\n");
}

#ifdef BACKEND_USES_CFRUNLOOP
 check_set_timer(new->tv);
#endif
#ifdef _REENTRANT
 if(num_threads>1)
{
struct timeval tmp;
ACCURATE_GETTIMEOFDAY(&tmp);
my_add_timeval(& new->tv, &tmp);
IF_CO (fprintf (stderr, "BACKEND[%d]: Adding call out at %ld.%ld "
"(current time is %ld.%ld)\n", me->id,
new->tv.tv_sec, new->tv.tv_usec,
tmp.tv_sec, tmp.tv_usec));
} else
#endif
 {
struct timeval tmp;
INACCURATE_GETTIMEOFDAY(&tmp);
my_add_timeval(& new->tv, &tmp);
IF_CO (fprintf (stderr, "BACKEND[%d]: Adding call out at %ld.%ld "
"(current_time is %ld.%ld)\n", me->id,
new->tv.tv_sec, new->tv.tv_usec,
tmp.tv_sec, tmp.tv_usec));
}

new->args = callable;
Pike_sp -= 2;
dmalloc_touch_svalue(Pike_sp);

adjust_up(me, me->num_pending_calls-1);
backend_verify_call_outs(me);

#ifdef _REENTRANT
 backend_wake_up_backend(me);
#endif
 
UNPROTECT_CALL_OUTS();
}
}

#ifdef Backend_CallOut_event_handler_defined
static void Backend_CallOut_event_handler(int ev) {
  switch(ev) {

#ifdef internal_init_Backend_CallOut_defined
  case PROG_EVENT_INIT: init_Backend_CallOut_struct(); break;

#endif /* internal_init_Backend_CallOut_defined */

#ifdef internal_exit_Backend_CallOut_defined
  case PROG_EVENT_EXIT: exit_Backend_CallOut_struct(); break;

#endif /* internal_exit_Backend_CallOut_defined */
  default: break; 
  }
}

#endif /* Backend_CallOut_event_handler_defined */
/*! @endclass
   */

#line 874 "/Users/hww3/devel/pike/src/backend.cmod"
#undef THIS
#define THIS THIS_BACKEND

static void backend_count_memory_in_call_outs(struct Backend_struct *me)
{
push_text("num_call_outs");
push_int(me->num_pending_calls);

push_text("call_out_bytes"); 
push_int64(me->call_heap_size * sizeof(struct Backend_CallOut_struct **)+
me->num_pending_calls * sizeof(struct Backend_CallOut_struct));

}

static void count_memory_in_call_outs(struct callback *UNUSED(foo),
void *UNUSED(bar),
void *UNUSED(gazonk))
{
backend_count_memory_in_call_outs(default_backend);
}

/*! @decl mapping(string:int) get_stats()
   *!
   *! Get some statistics about the backend.
   *!
   *! @returns
   *!   Returns a mapping with the follwoing content:
   *!   @mapping
   *!     @member int "num_call_outs"
   *!       The number of active call-outs.
   *!     @member int "call_out_bytes"
   *!       The amount of memory used by the call-outs.
   *!   @endmapping
   */
#define f_Backend_get_stats_defined

#ifdef f_Backend_get_stats_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_Backend_get_stats_fun_num = 0;

#endif /* f_Backend_get_stats_fun_num_used */
DEFAULT_CMOD_STORAGE void f_Backend_get_stats(INT32 args) {
#line 908 "/Users/hww3/devel/pike/src/backend.cmod"
if(args != 0) wrong_number_of_args_error("get_stats",args,0);
{
struct svalue *save_sp = Pike_sp;
backend_count_memory_in_call_outs(THIS);
f_aggregate_mapping(Pike_sp - save_sp);
stack_pop_n_elems_keep_top(args);
}

}
#line 916 "/Users/hww3/devel/pike/src/backend.cmod"
/* FIXME */
#if 0
 MARK 
{
int e;
struct Backend_struct *me=THIS;

for(e=0;e<me->num_pending_calls;e++)
{
gc_mark(CALL(e)->args,0,"call out args");
}
}
#endif

/*! @decl array call_out(function f, float|int delay, mixed ... args)
 *!
 *! Make a delayed call to a function.
 *!
 *! @[call_out()] places a call to the function @[f] with the argument
 *! @[args] in a queue to be called in about @[delay] seconds.
 *!
 *! If @[f] returns @expr{-1@}, no other call out or callback will be
 *! called by the backend in this round. I.e. @[`()] will return right
 *! away. For the main backend that means it will immediately start
 *! another round and check files and call outs anew.
 *!
 *! @returns
 *!   Returns a call_out identifier that identifies this call_out.
 *!   This value can be sent to eg @[find_call_out()] or @[remove_call_out()].
 *!
 *! @seealso
 *!   @[remove_call_out()], @[find_call_out()], @[call_out_info()],
 *!   @[CallOut]
 */
#define f_Backend_call_out_defined

#ifdef f_Backend_call_out_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_Backend_call_out_fun_num = 0;

#endif /* f_Backend_call_out_fun_num_used */
DEFAULT_CMOD_STORAGE void f_Backend_call_out(INT32 args) {
#line 950 "/Users/hww3/devel/pike/src/backend.cmod"
struct svalue * f;
#line 950 "/Users/hww3/devel/pike/src/backend.cmod"
struct svalue * t;
#line 950 "/Users/hww3/devel/pike/src/backend.cmod"
struct svalue * rest;
#line 950 "/Users/hww3/devel/pike/src/backend.cmod"
if(args < 2) wrong_number_of_args_error("call_out",args,2);
#line 950 "/Users/hww3/devel/pike/src/backend.cmod"
f=Pike_sp+0-args; dmalloc_touch_svalue(Pike_sp+0-args);
#line 950 "/Users/hww3/devel/pike/src/backend.cmod"
t=Pike_sp+1-args; dmalloc_touch_svalue(Pike_sp+1-args);
#line 950 "/Users/hww3/devel/pike/src/backend.cmod"
if (args > 2) {
  INT32 argcnt = 0;
  do {
    dmalloc_touch_svalue(Pike_sp+2+argcnt-args);
#line 950 "/Users/hww3/devel/pike/src/backend.cmod"
  } while (++argcnt < args-2);
  rest=Pike_sp+2-args;
} else rest = NULL;
#line 951 "/Users/hww3/devel/pike/src/backend.cmod"
{
struct svalue tmp;
struct object *co;
struct Backend_CallOut_struct *c;

if(args<2)
SIMPLE_TOO_FEW_ARGS_ERROR("call_out", 2);

if(TYPEOF(*t) != T_INT && TYPEOF(*t) != T_FLOAT)
SIMPLE_BAD_ARG_ERROR("call_out", 2, "int|float");

/* Swap, for compatibility */
tmp = Pike_sp[-args];
Pike_sp[-args] = Pike_sp[1-args];
Pike_sp[1-args] = tmp;

apply_current(Backend_CallOut_program_fun_num, args);
args = 1;

get_all_args("low_call_out", args, "%o", &co);

c = get_storage(co, Backend_CallOut_program);

if (!c) Pike_error("Unexpected object from CallOut.\n");

ref_push_array(c->args);

stack_pop_n_elems_keep_top(args);
}

}
#line 981 "/Users/hww3/devel/pike/src/backend.cmod"
/* Assumes current_time is correct on entry. */
static int backend_do_call_outs(struct Backend_struct *me)
{
int call_count = 0;
int args;
struct timeval tmp, now;
backend_verify_call_outs(me);

INACCURATE_GETTIMEOFDAY(&now);
tmp.tv_sec = now.tv_sec;
tmp.tv_usec = now.tv_usec;
tmp.tv_sec++;
while(me->num_pending_calls &&
my_timercmp(&CALL(0)->tv, <= ,&now))
{
struct timeval now;
/* unlink call out */
struct Backend_CallOut_struct *cc;
DECLARE_PROTECT_CALL_OUTS;

PROTECT_CALL_OUTS();
cc=CALL(0);
if(--me->num_pending_calls)
{
MOVECALL(0,me->num_pending_calls);
adjust_down(me, 0);
}
CALL_(me->num_pending_calls) = NULL;
UNPROTECT_CALL_OUTS();
cc->pos = -1;

args = cc->args->size;
if (cc->args->refs == 1) {
push_array_items(cc->args);
} else {
/* Somebody else also has references to the call_out id array.
	    *
	    * We need to clear it to reduce garbage.
	    */
add_ref(cc->args);
push_array_items(cc->args);
clear_array(cc->args);
free_array(cc->args);
}
cc->args = NULL;
/* Unlink the call_out from the call_hash hash table directly.
	  *
	  * NB: Don't wait for the EXIT callback to run, as this
	  *     would cause a race-condition with respect to
	  *     - Growing the call_hash hash table (which would
	  *       leave live pointers to the old hash table).
	  *     - backend_find_call_out() (which would dereference
	  *       cc->args (ie NULL)).
	  *     until destruct_objects_to_destruct() is run.
	  */
EXIT_CO(cc);
free_object(cc->this);

check_destructed(Pike_sp - args);
if(TYPEOF(Pike_sp[-args]) != T_INT)
{
IF_CO(
fprintf(stderr, "[%d]BACKEND[%d]: backend_do_call_outs: "
"calling call out ", THR_NO, me->id);
print_svalue (stderr, Pike_sp - args);
fputc ('\n', stderr);
);
call_count++;
f_call_function(args);
if (TYPEOF(Pike_sp[-1]) == T_INT && Pike_sp[-1].u.integer == -1) {
pop_stack();
backend_verify_call_outs(me);
call_count = -call_count;
break;
}
else
pop_stack();
}else{
IF_CO(fprintf(stderr, "[%d]BACKEND[%d]: backend_do_call_outs: "
"ignoring destructed call out\n", THR_NO, me->id));
pop_n_elems(args);
}
backend_verify_call_outs(me);

ACCURATE_GETTIMEOFDAY(&now);
if(my_timercmp(&now, > , &tmp)) break;
}

IF_CO (
if (me->num_pending_calls)
fprintf (stderr,
"BACKEND[%d]: backend_do_call_outs: stopping with %d "
"call outs left, closest with time %ld.%ld "
"(current_time %ld.%ld, limit at %ld.%ld)\n",
me->id, me->num_pending_calls,
CALL(0)->tv.tv_sec, CALL(0)->tv.tv_usec,
now.tv_sec, now.tv_usec,
tmp.tv_sec, tmp.tv_usec);
else
fprintf (stderr, "BACKEND[%d]: backend_do_call_outs: "
"no outstanding call outs\n",
me->id);
);

return call_count;
}

/* NB: Calls Pike code, so MUST NOT be used in a PROTECT_CALL_OUTS()
    *     context.
    *
    *     Note that a non-NULL return value only indicates that the
    *     fun was found before the calls of is_eq(), which may have
    *     caused the call_out to be removed.
    */
static struct array *backend_find_call_out_info(struct Backend_struct *me,
struct svalue *fun)
{
size_t hval, fun_hval;
struct Backend_CallOut_struct *c;
struct svalue *save_sp = Pike_sp;
DECLARE_PROTECT_CALL_OUTS;

if(!me->num_pending_calls) return NULL;

PROTECT_CALL_OUTS();

if(TYPEOF(*fun) == T_ARRAY)
{
hval=PTR_TO_INT(fun->u.array);
hval%=me->hash_size;
for(c=me->call_hash[hval].arr;c;c=c->next_arr)
{
if(c->args == fun->u.array)
{
#ifdef PIKE_DEBUG
 if(CALL(c->pos) != c)
Pike_fatal("Call_out->pos not correct!\n");
#endif
 UNPROTECT_CALL_OUTS();
add_ref(c->args);
return c->args;
}
}
}

fun_hval=hash_svalue(fun);
hval = fun_hval % me->hash_size;
for(c=me->call_hash[hval].fun;c;c=c->next_fun)
{
if(c->fun_hval == fun_hval)
{
#ifdef PIKE_DEBUG
 if(CALL(c->pos) != c)
Pike_fatal("Call_out->pos not correct!\n");
#endif
 /* Delay the is_eq() call until we've finished
	    * scanning the hash table.
	    */
ref_push_array(c->args);
}
}
UNPROTECT_CALL_OUTS();

/* Note: is_eq() may call Pike code (which we want),
	*       however, we can't let it modify the hash
	*       table while we're scanning it.
	*/
while (Pike_sp > save_sp) {
struct array *res = Pike_sp[-1].u.array;
/* FIXME: Use CYCLIC! */
if (is_eq(fun, ITEM(res))) {
add_ref(res);
pop_n_elems(Pike_sp - save_sp);
return res;
}
pop_stack();
}

return NULL;
}

/* Typically used in a PROTECT_CALL_OUTS() context. */
static int backend_find_call_out(struct Backend_struct *me,
struct array *co_info)
{
size_t hval, fun_hval;
struct Backend_CallOut_struct *c;

if(!co_info || !me->num_pending_calls) return -1;

hval=PTR_TO_INT(co_info);
hval%=me->hash_size;
for(c=me->call_hash[hval].arr;c;c=c->next_arr)
{
if(c->args == co_info)
{
#ifdef PIKE_DEBUG
 if(CALL(c->pos) != c)
Pike_fatal("Call_out->pos not correct!\n");
#endif
 return c->pos;
}
}

return -1;
}

/*! @decl int _do_call_outs()
 *!
 *! Do all pending call_outs.
 *!
 *! This function runs all pending call_outs that should have been
 *! run if Pike returned to the backend.  It should not be used in
 *! normal operation.
 *!
 *! As a side-effect, this function sets the value returned by
 *! @[time(1)] to the current time.
 *!
 *! @returns
 *! Zero if no call outs were called, nonzero otherwise.
 *!
 *! @seealso
 *! @[call_out()], @[find_call_out()], @[remove_call_out()]
 */
#define f_Backend_cq__do_call_outs_defined

#ifdef f_Backend_cq__do_call_outs_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_Backend_cq__do_call_outs_fun_num = 0;

#endif /* f_Backend_cq__do_call_outs_fun_num_used */
DEFAULT_CMOD_STORAGE void f_Backend_cq__do_call_outs(INT32 args) {
#line 1205 "/Users/hww3/devel/pike/src/backend.cmod"
if(args != 0) wrong_number_of_args_error("_do_call_outs",args,0);
{
INVALIDATE_CURRENT_TIME();
do { INT_TYPE ret_=(backend_do_call_outs(THIS));  push_int(ret_); return; }while(0);
#line 1209 "/Users/hww3/devel/pike/src/backend.cmod"
}

}
/*! @decl int find_call_out(function f)
 *! @decl int find_call_out(array id)
 *!
 *! Find a call out in the queue.
 *!
 *! This function searches the call out queue. If given a function as
 *! argument, it looks for the first call out scheduled to that function.
 *!
 *! The argument can also be a call out id as returned by @[call_out()], in
 *! which case that call_out will be found (Unless it has already been
 *! called).
 *!
 *! @returns
 *!   @[find_call_out()] returns the remaining time in seconds before that
 *!   call_out will be executed. If no call_out is found,
 *!   @[zero_type](@[find_call_out](f)) will return 1.
 *!
 *! @seealso
 *!   @[call_out()], @[remove_call_out()], @[call_out_info()]
 */
#define f_Backend_find_call_out_defined

#ifdef f_Backend_find_call_out_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_Backend_find_call_out_fun_num = 0;

#endif /* f_Backend_find_call_out_fun_num_used */
DEFAULT_CMOD_STORAGE void f_Backend_find_call_out(INT32 args) {
#line 1231 "/Users/hww3/devel/pike/src/backend.cmod"
struct svalue * f;
#line 1231 "/Users/hww3/devel/pike/src/backend.cmod"
if(args != 1) wrong_number_of_args_error("find_call_out",args,1);
#line 1231 "/Users/hww3/devel/pike/src/backend.cmod"
f=Pike_sp+0-1; dmalloc_touch_svalue(Pike_sp+0-1);
{
struct Backend_struct *me=THIS;
struct array *co_info;

backend_verify_call_outs(me);

co_info = backend_find_call_out_info(me, f);

if(!co_info)
{
/* NB: This is a very exotic value! */
SET_SVAL(*Pike_sp, T_INT, NUMBER_UNDEFINED, integer, -1);
Pike_sp++;
} else {
int e;
struct timeval now;
DECLARE_PROTECT_CALL_OUTS;
PROTECT_CALL_OUTS();
e = backend_find_call_out(me, co_info);
pop_n_elems(args);
free_array(co_info);
if (e == -1) {
/* NB: This is a very exotic value! */
SET_SVAL(*Pike_sp, T_INT, NUMBER_UNDEFINED, integer, -1);
Pike_sp++;
}else{
INACCURATE_GETTIMEOFDAY(&now);
push_int(CALL(e)->tv.tv_sec - now.tv_sec);
}
UNPROTECT_CALL_OUTS();
}
backend_verify_call_outs(me);
}

}
/*! @decl int remove_call_out(function f)
 *! @decl int remove_call_out(array id)
 *!
 *! Remove a call out from the call out queue.
 *!
 *! This function finds the first call to the function @[f] in the call_out
 *! queue and removes it.  You can also give a call out id as argument (as
 *! returned by @[call_out()]).
 *!
 *! @returns
 *!   The remaining time in seconds left to that call out will be returned.
 *!   If no call_out was found, @[zero_type](@[remove_call_out](@[f]))
 *!   will return 1.
 *!
 *! @seealso
 *!   @[call_out_info()], @[call_out()], @[find_call_out()]
 */
#define f_Backend_remove_call_out_defined

#ifdef f_Backend_remove_call_out_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_Backend_remove_call_out_fun_num = 0;

#endif /* f_Backend_remove_call_out_fun_num_used */
DEFAULT_CMOD_STORAGE void f_Backend_remove_call_out(INT32 args) {
#line 1283 "/Users/hww3/devel/pike/src/backend.cmod"
struct svalue * f;
#line 1283 "/Users/hww3/devel/pike/src/backend.cmod"
if(args != 1) wrong_number_of_args_error("remove_call_out",args,1);
#line 1283 "/Users/hww3/devel/pike/src/backend.cmod"
f=Pike_sp+0-1; dmalloc_touch_svalue(Pike_sp+0-1);
{
struct Backend_struct *me=THIS;
struct array *co_info;

backend_verify_call_outs(me);

co_info = backend_find_call_out_info(me, f);

if(!co_info)
{
/* NB: This is a very exotic value! */
SET_SVAL(*Pike_sp, T_INT, NUMBER_UNDEFINED, integer, -1);
Pike_sp++;
} else {
int e;
DECLARE_PROTECT_CALL_OUTS;

PROTECT_CALL_OUTS();
backend_verify_call_outs(me);
e = backend_find_call_out(me, co_info);
backend_verify_call_outs(me);
if(e!=-1)
{
struct Backend_CallOut_struct *c = CALL(e);
struct timeval now;

INACCURATE_GETTIMEOFDAY(&now);
IF_CO (fprintf (stderr, "BACKEND[%d]: Removing call out at %ld.%ld "
"(current_time is %ld.%ld)\n", me->id,
c->tv.tv_sec, c->tv.tv_usec,
now.tv_sec, now.tv_usec));
pop_n_elems(args);
push_int(c->tv.tv_sec - now.tv_sec);

me->num_pending_calls--;
if(e!=me->num_pending_calls)
{
MOVECALL(e,me->num_pending_calls);
adjust(me,e);
}
CALL_(me->num_pending_calls) = NULL;
c->pos = -1;

free_object(c->this);
}else{
pop_n_elems(args);
/* NB: This is a very exotic value! */
SET_SVAL(*Pike_sp, T_INT, NUMBER_UNDEFINED, integer, -1);
Pike_sp++;
}

/* Make sure not to keep any references in the
	* now stale co_info array. */
clear_array(co_info);

free_array(co_info);
backend_verify_call_outs(me);
UNPROTECT_CALL_OUTS();
}
}

}
#line 1345 "/Users/hww3/devel/pike/src/backend.cmod"
/* return an array containing info about all call outs:
 * ({  ({ delay, caller, function, args, ... }), ... })
 */
struct array *backend_get_all_call_outs(struct Backend_struct *me)
{
int e;
struct array *ret;
struct timeval now;
ONERROR err;
DECLARE_PROTECT_CALL_OUTS;

backend_verify_call_outs(me);
PROTECT_CALL_OUTS();
ret=allocate_array_no_init(0, me->num_pending_calls);
SET_ONERROR(err, do_free_array, ret);
ret->type_field = BIT_ARRAY;
if(me->num_pending_calls) INACCURATE_GETTIMEOFDAY(&now);
for(e=0;e<me->num_pending_calls;e++)
{
struct array *v;
v=allocate_array_no_init(CALL(e)->args->size+2, 0);
ITEM(v)[0].u.integer=CALL(e)->tv.tv_sec - now.tv_sec;

/* FIXME: ITEM(v)[1] used to be the current object
	  *        from when the call_out was created, but
	  *        that is always the backend since the
	  *        backend.cmod rewrite.
	  *        Now we just leave it zero.
	  */
v->type_field = BIT_INT;

v->type_field |=
assign_svalues_no_free(ITEM(v)+2,
ITEM(CALL(e)->args),
CALL(e)->args->size,BIT_MIXED);

SET_SVAL(ITEM(ret)[e], T_ARRAY, 0, array, v);
ret->size++;
}
UNSET_ONERROR(err);
UNPROTECT_CALL_OUTS();
return ret;
}

/*! @decl array(array) call_out_info()
 *!
 *! Get info about all call_outs.
 *!
 *! This function returns an array with one entry for each entry in the
 *! call out queue. The first in the queue will be at index 0. Each index
 *! contains an array that looks like this:
 *! @array
 *!   @elem int time_left
 *!     Time remaining in seconds until the call_out is to be performed.
 *!   @elem int(0..0) zero
 *!     Used to be the object that scheduled the call_out.
 *!   @elem function fun
 *!     Function to be called.
 *!   @elem mixed ... args
 *!     Arguments to the function.
 *! @endarray
 *!
 *! @seealso
 *!   @[call_out()], @[find_call_out()], @[remove_call_out()]
 */
#define f_Backend_call_out_info_defined

#ifdef f_Backend_call_out_info_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_Backend_call_out_info_fun_num = 0;

#endif /* f_Backend_call_out_info_fun_num_used */
DEFAULT_CMOD_STORAGE void f_Backend_call_out_info(INT32 args) {
#line 1410 "/Users/hww3/devel/pike/src/backend.cmod"
if(args != 0) wrong_number_of_args_error("call_out_info",args,0);
{
do { struct array * ret_=(backend_get_all_call_outs(THIS));  push_array(ret_); return; }while(0);
#line 1413 "/Users/hww3/devel/pike/src/backend.cmod"
}

}
#line 1415 "/Users/hww3/devel/pike/src/backend.cmod"
/*
   * FD box handling
   */

#define GET_ACTIVE_BOX(ME, FD)						\
   ((ME)->fd_boxes[(FD) - (ME)->fd_boxes_start])

#define GET_BOX(ME, FD)							\
   ((FD) < 0 ?								\
    (ME)->inactive_boxes[~(FD)] :					\
    (ME)->fd_boxes[(FD) - (ME)->fd_boxes_start])

#define SAFE_GET_ACTIVE_BOX(ME, FD)					\
   ((FD) >= (ME)->fd_boxes_start &&					\
    (FD) < (ME)->fd_boxes_start + (ME)->fd_boxes_size ?			\
    GET_ACTIVE_BOX (ME, FD) : NULL)


static struct fd_callback_box *safe_get_box (struct Backend_struct *me,
int fd)
{
if (fd < 0) {
fd = ~fd;
if (fd < me->inactive_boxes_size) {
struct fd_callback_box *box = me->inactive_boxes[fd];
/* Avoid free list pointers. */
if ((struct fd_callback_box **) box < me->inactive_boxes ||
(struct fd_callback_box **) box >=
(me->inactive_boxes + me->inactive_boxes_size))
return box;
}
}
else {
fd -= me->fd_boxes_start;
if (fd >= 0 && fd < me->fd_boxes_size)
return me->fd_boxes[fd];
}
return NULL;
}

/**
    * Get the fd_callback_box corresponding to an fd.
    */
PMOD_EXPORT struct fd_callback_box
*get_fd_callback_box_for_fd( struct Backend_struct *me, int fd )
{
return safe_get_box( me, fd );
}

/* NOTE: Some versions of AIX seem to have a
 *         #define events reqevents
 *       in one of the poll headerfiles. This will break
 *       the fd_box event handling.
 */
#undef events

/* Make sure the WANT_EVENT() macro is useable... */
#undef READ
#undef WRITE
#undef READ_OOB
#undef WRITE_OOB
#undef FS_EVENT
#undef ERROR

#define WANT_EVENT(BOX, WHAT)						\
   ((BOX) && (BOX)->events & PIKE_CONCAT (PIKE_BIT_FD_, WHAT))

#define FOR_EACH_ACTIVE_FD_BOX(ME, BOX_VAR)				\
   struct Backend_struct *me_ = (ME);					\
   struct fd_callback_box *BOX_VAR, **boxes_ = me_->fd_boxes;		\
   int b_, max_ = me_->fd_boxes_size;					\
   for (b_ = 0; b_ < max_; b_++)					\
     if ((BOX_VAR = boxes_[b_]))

#define FOR_EACH_INACTIVE_FD_BOX(ME, BOX_VAR)				\
   struct Backend_struct *me_ = (ME);					\
   struct fd_callback_box *BOX_VAR, **boxes_ = me_->inactive_boxes;	\
   int b_ = 0, max_ = me_->inactive_boxes_size;				\
   for (b_ = 0; b_ < max_; b_++)					\
     if ((BOX_VAR = boxes_[b_]) &&					\
	 /* Avoid free list pointers. */				\
	 ((struct fd_callback_box **) BOX_VAR < boxes_ ||		\
	  (struct fd_callback_box **) BOX_VAR >= boxes_+max_))

#ifdef PIKE_DEBUG
 static void check_box (struct fd_callback_box *box, int fd)
{
struct Backend_struct *me;
if (!box) return;
if (!(me = box->backend))
Pike_fatal("fd_callback_box not hooked to any backend.\n");
if (fd == INT_MAX)
fd = box->fd;
else if (fd != box->fd)
Pike_fatal("fd in callback box doesn't contain the expected fd.\n");
if (safe_get_box (me, fd) != box)
Pike_fatal("fd_callback_box not hooked in correctly for fd %d.\n",
box->fd);
}
#else
#  define check_box(box, fd) do {} while (0)
#endif

static void add_fd_box (struct fd_callback_box *box)
{
struct Backend_struct *me = box->backend;
int fd = box->fd;

#ifdef PIKE_DEBUG
 if (fd >= 0) {
struct fd_callback_box *old_box = SAFE_GET_ACTIVE_BOX (me, fd);
if (old_box == box)
Pike_fatal ("The box is already hooked in.\n");
if (old_box)
Pike_fatal ("There's another callback box %p for fd %d.\n",
old_box, fd);
if (get_backend_for_fd (fd) && get_backend_for_fd (fd) != me)
Pike_fatal ("The fd is allocated to another backend.\n");
}
else {
int i;
for (i = 0; i < me->inactive_boxes_size; i++)
if (me->inactive_boxes[i] == box)
Pike_fatal ("The box is already hooked in.\n");
}
#endif

if (fd >= 0) {
low_set_backend_for_fd (fd, me);

if (!me->fd_boxes_size) {
/* Start small since backends with only a single fd aren't uncommon. */
me->fd_boxes_size = 4;
me->fd_boxes = calloc (sizeof (me->fd_boxes[0]), me->fd_boxes_size);
if (!me->fd_boxes)
Pike_fatal ("Out of memory in backend::add_fd_box(): "
"Tried to allocate %d fd_callback_box pointers\n",
me->fd_boxes_size);
me->fd_boxes_start = fd;
fd = 0;
}

else if (fd < me->fd_boxes_start) {
int old_size = me->fd_boxes_size, shift = me->fd_boxes_size;
struct fd_callback_box **old_boxes = me->fd_boxes;
IF_PD(fprintf(stderr, "me->fd_boxes: %p (%d ==> %d)\n",
me->fd_boxes, me->fd_boxes_start, fd));
while (fd < me->fd_boxes_start - shift) shift *= 2;
if (me->fd_boxes_start - shift < 0) shift = me->fd_boxes_start;
me->fd_boxes_start -= shift;
me->fd_boxes_size += shift;
debug_malloc_touch(me->fd_boxes);
me->fd_boxes =
realloc (me->fd_boxes, sizeof (me->fd_boxes[0]) * me->fd_boxes_size);
if (!me->fd_boxes)
Pike_fatal ("Out of memory in backend::add_fd_box(): "
"Tried to allocate %d fd_callback_box pointers\n",
me->fd_boxes_size);
memmove (me->fd_boxes + shift, me->fd_boxes,
sizeof (me->fd_boxes[0]) * old_size);
memset (me->fd_boxes, 0, sizeof (me->fd_boxes[0]) * shift);
debug_malloc_touch(me->fd_boxes);
fd -= me->fd_boxes_start;
}

else {
fd -= me->fd_boxes_start;
if (fd >= me->fd_boxes_size) {
int old_size=me->fd_boxes_size;
while(fd >= me->fd_boxes_size) me->fd_boxes_size*=2;
debug_malloc_touch(me->fd_boxes);
me->fd_boxes =
realloc(me->fd_boxes, sizeof(me->fd_boxes[0]) * me->fd_boxes_size);
if( !me->fd_boxes )
Pike_fatal("Out of memory in backend::add_fd_box(): "
"Tried to allocate %d fd_callback_box pointers\n",
me->fd_boxes_size);
memset(me->fd_boxes+old_size,
0,
(me->fd_boxes_size-old_size)*sizeof(me->fd_boxes[0]));
debug_malloc_touch(me->fd_boxes);
}
}

me->fd_boxes[fd] = box;
}

else { /* Add an inactive box. */
int pos;

if (!me->free_inactive_box) {
pos = me->inactive_boxes_size;
if (!me->inactive_boxes_size)
me->inactive_boxes_size = 4;
else
me->inactive_boxes_size *= 2;
if (!me->inactive_boxes)
me->inactive_boxes =
malloc (sizeof (me->inactive_boxes[0]) * me->inactive_boxes_size);
else {
#ifdef PIKE_DEBUG
 {
struct fd_callback_box **p, **boxes = me->inactive_boxes;
int i;
int max = pos; /* me->inactive_boxes_size before enlargement. */
for (i = 0; i < max; i++)
if ((p = (struct fd_callback_box **) boxes[i]) &&
p >= boxes && p < boxes + max)
Pike_fatal ("Still got free list pointers in inactive box "
"list that is about to be enlarged.\n");
}
#endif
 me->inactive_boxes =
realloc (me->inactive_boxes,
sizeof (me->inactive_boxes[0]) * me->inactive_boxes_size);
}
if (!me->inactive_boxes)
Pike_fatal ("Out of memory in backend::add_fd_box(): "
"Tried to allocate %d inactive "
"fd_callback_box pointers.\n",
me->inactive_boxes_size);
me->free_inactive_box = me->inactive_boxes + pos;
while (++pos < me->inactive_boxes_size)
me->inactive_boxes[pos - 1] =
(struct fd_callback_box *) (me->inactive_boxes + pos);
me->inactive_boxes[pos - 1] = NULL;
}

pos = me->free_inactive_box - me->inactive_boxes;
me->free_inactive_box =
(struct fd_callback_box **)*me->free_inactive_box;

me->inactive_boxes[pos] = box;
box->fd = ~pos;
}
}

static void remove_fd_box (struct fd_callback_box *box)
{
struct Backend_struct *me = box->backend;
int fd = box->fd;
check_box (box, INT_MAX);

/* FIXME: Shrink arrays? */

if (fd >= 0) {
low_set_backend_for_fd (fd, NULL);
me->fd_boxes[fd - me->fd_boxes_start] = NULL;
}
else {
fd = ~fd;
me->inactive_boxes[fd] =
(struct fd_callback_box *)me->free_inactive_box;
me->free_inactive_box = me->inactive_boxes + fd;
}
}

static void update_fd_set (struct Backend_struct *me, int fd,
int old_events, int new_events, int flags)
{
if (fd < 0) return;

#ifdef __NT__
 if (new_events &&
!(fd_query_properties(fd, fd_CAN_NONBLOCK) & fd_CAN_NONBLOCK)) {
Pike_fatal("update_fd_set() on non-socket!\n");
}
#endif /* __NT__ */

IF_PD(fprintf(stderr, "update_fd_set(%p, %d, 0x%08x, 0x%08x)\n",
me, fd, old_events, new_events));

if (me->update_fd_set_handler) {
me->update_fd_set_handler(me, me->handler_data,
fd, old_events, new_events, flags);
} else {
Pike_fatal("No update_fd_set_handler set[%p, %d, 0x%04x, 0x%04x].\n");
}
}

/**
    * Update the backend that the box is associated with to
    * a new set of events to notify for.
    */
PMOD_EXPORT void hook_fd_callback_box (struct fd_callback_box *box)
{
struct Backend_struct *me = box->backend;
int fd = box->fd;
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: hook_fd_callback_box: "
"fd %d, events 0x%x, object %p\n",
THR_NO, me->id, fd, box->events, box->ref_obj));
#ifdef PIKE_DEBUG
 if (!me) Pike_fatal ("Backend not set.\n");
#endif
#ifdef __NT__
 if ((fd >= 0) && box->events &&
!(fd_query_properties(fd, fd_CAN_NONBLOCK) & fd_CAN_NONBLOCK)) {
Pike_fatal("hook_fd_callback_box() on non-socket!\n"
"  fd: %d\n"
"  events: 0x%04x\n"
"  fd_properties: 0x%04x\n",
fd, box->events, fd_query_properties(fd, fd_CAN_NONBLOCK));
}
#endif /* __NT__ */
 add_fd_box (box);
if (fd >= 0) update_fd_set (me, fd, 0, box->events, box->flags);
if (box->ref_obj && box->events) add_ref (box->ref_obj);
}

/**
   * Unlink the box from the active list it is on (if any),
   * and return 1 if it was active (and thus needs to be freed).
   */
static int unlink_box(struct fd_callback_box *box)
{
if (box->next) {
/* The box is active in some backend. Unlink it. */
struct fd_callback_box *pred = box->next;
/* Find the predecessor. */
while (pred->next != box) {
pred = pred->next;
}
pred->next = box->next;
box->next = NULL;
return 1;
}
return 0;
}

/**
   * Unhook a box from its associated backend (if any),
   * and clear any events.
   */
PMOD_EXPORT void unhook_fd_callback_box (struct fd_callback_box *box)
{
/* Accept an unhooked box; can happen when we're called from an
     * object exit hook due to being freed by free_object below. */
if (!box->backend) {
IF_PD(fprintf(stderr,
"[%d]BACKEND[unhooked box]: unhook_fd_callback_box: "
"fd %d, object %p\n", THR_NO, box->fd, box->ref_obj));
return;
}

check_box (box, INT_MAX);
IF_PD(fprintf(stderr,
"[%d]BACKEND[%d]: unhook_fd_callback_box: fd %d, object %p\n",
THR_NO, box->backend->id, box->fd, box->ref_obj));

if (box->fd >= 0) {
update_fd_set (box->backend, box->fd, box->events, 0, box->flags);
}
remove_fd_box (box);
box->backend = NULL;
/* Make sure no further callbacks are called on this box. */
box->revents = 0;
box->rflags = 0;

/* Unlink the box from the active list in case it is there,
     * otherwise the active list may get cut, which could cause
     * the remaining boxes on the list to be lost from the backend..
     */
if (unlink_box(box) && box->ref_obj) {
/* Use gc safe method to allow calls from within the gc. */
/* box->ref_obj is only converted from a counted to
       * non-counted ref, so it shouldn't be clobbered by the free. */
union anything u;
u.object = box->ref_obj;
gc_free_short_svalue (&u, T_OBJECT);
}

if (box->ref_obj && box->events) {
/* Use gc safe method to allow calls from within the gc. */
/* box->ref_obj is only converted from a counted to
       * non-counted ref, so it shouldn't be clobbered by the free. */
union anything u;
u.object = box->ref_obj;
gc_free_short_svalue (&u, T_OBJECT);
box->events = 0;
}
}

/**
   * Set the event mask for a hooked box.
   */
PMOD_EXPORT void set_fd_callback_events (struct fd_callback_box *box,
int events, int flags)
{
int old_events = box->events;
check_box (box, INT_MAX);
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: set_fd_callback_events: "
"fd %d, events from 0x%x to 0x%x, object %p\n",
THR_NO, box->backend->id, box->fd, old_events, events,
box->ref_obj));
if (box->fd >= 0) {
update_fd_set (box->backend, box->fd, old_events, events, flags);
}
box->events = events;
box->flags = flags;

if (box->ref_obj) {
if (!old_events) {
if (events) add_ref (box->ref_obj);
}
else
if (!events) {
/* Use gc safe method to allow calls from within the gc. */
/* box->ref_obj is only converted from a counted to
	   * non-counted ref, so it shouldn't be clobbered by the free. */
union anything u;
u.object = box->ref_obj;
gc_free_short_svalue (&u, T_OBJECT);
}
}
}

/**
   * Change the backend that a box is to be associated with.
   */
PMOD_EXPORT void change_backend_for_box (struct fd_callback_box *box,
struct Backend_struct *new)
{
struct Backend_struct *old = box->backend;
if (old) check_box (box, INT_MAX);

#ifdef PIKE_DEBUG
 if (!new) Pike_fatal ("New backend is invalid.\n");
#endif

IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: change_backend_for_box: "
"fd %d, new backend %d\n",
THR_NO, old?old->id:-1, box->fd, new->id));

if (old != new) {
if (old) {
if (box->fd >= 0) {
update_fd_set (old, box->fd, box->events, 0, box->flags);
}
remove_fd_box (box);

/* Unlink the box from the active in the old backend,
	 * and free it if it was there.
	 */
if (unlink_box(box) && box->ref_obj) {
free_object(box->ref_obj);
}
}
box->backend = new;
add_fd_box (box);
if (box->fd >= 0) {
update_fd_set (new, box->fd, 0, box->events, box->flags);
}
}
}

/**
   * Change the fd that a box refers to.
   */
PMOD_EXPORT void change_fd_for_box (struct fd_callback_box *box, int new_fd)
{
int old_fd = box->fd;

if (!box->backend) {
/* Convenience so that the caller doesn't have to check if the
       * box is hooked in. */
IF_PD(fprintf(stderr, "[%d]BACKEND[unhooked box]: change_fd_for_box: "
"fd from %d to %d, obj: %p\n",
THR_NO, old_fd, new_fd, box->ref_obj));
box->fd = new_fd;
box->revents = 0;
box->rflags = 0;
}

else {
check_box (box, INT_MAX);

if (old_fd >= 0 ? old_fd != new_fd : new_fd >= 0) {
if (old_fd >= 0) {
update_fd_set (box->backend, old_fd, box->events, 0, box->flags);
}
remove_fd_box (box);
box->fd = new_fd;
add_fd_box (box);
new_fd = box->fd;
box->revents = 0;
box->rflags = 0;
if (new_fd >= 0) {
update_fd_set (box->backend, new_fd, 0, box->events, box->flags);
}
}

IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: change_fd_for_box: "
"fd from %d to %d\n",
THR_NO, box->backend->id, old_fd, new_fd));
}
}

static void do_free_fd_box(struct fd_callback_box *box)
{
if (box->ref_obj) free_object(box->ref_obj);
}

static void do_free_fd_list(struct fd_callback_box *fd_list)
{
struct fd_callback_box *box;
while ((box = fd_list->next)) {
fd_list->next = box->next;
box->next = NULL;
if (box->ref_obj) free_object(box->ref_obj);
}
}

#ifdef PIKE_DEBUG

static void backend_do_debug(struct Backend_struct *me)
{
backend_verify_call_outs(me);

if (me->debug_handler) {
me->debug_handler(me, me->handler_data);
}

{FOR_EACH_ACTIVE_FD_BOX (me, box) check_box (box, INT_MAX);}
{FOR_EACH_INACTIVE_FD_BOX (me, box) check_box (box, INT_MAX);}
}

#endif	/* PIKE_DEBUG */

/*! @decl float|int(0..0) `()(void|float|int(0..0) sleep_time)
   *!   Perform one pass through the backend.
   *!
   *!   Calls any outstanding call-outs and non-blocking I/O
   *!   callbacks that are registred in this backend object.
   *!
   *! @param sleep_time
   *!   Wait at most @[sleep_time] seconds. The default when
   *!   unspecified or the integer @expr{0@} is no time limit.
   *!
   *! @returns
   *!   If the backend did call any callbacks or call outs then the
   *!   time spent in the backend is returned as a float. Otherwise
   *!   the integer @expr{0@} is returned.
   *!
   *! @note
   *!   If multiple threads concurrently call this function, then:
   *!   @ul
   *!     @item
   *!       One of the threads will be the controlling thread.
   *!     @item
   *!       All callbacks will be called from the controlling thread.
   *!     @item
   *!       All threads will be woken up when the controlling thread
   *!       is done. This may be prematurely if the controlling thread
   *!       had a shorter timeout.
   *!   @endul
   *!
   *! @note
   *!   The backend may also be woken up prematurely if the set
   *!   of events to monitor is changed.
   *!
   *! @note
   *!   Multiple concurrent calls was not supported prior to Pike 8.0.
   *!
   *! @seealso
   *!   @[Pike.DefaultBackend], @[main()]
   */
#define f_Backend_cq__backtick_28_29_defined

#ifdef f_Backend_cq__backtick_28_29_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_Backend_cq__backtick_28_29_fun_num = 0;

#endif /* f_Backend_cq__backtick_28_29_fun_num_used */
#line 1986 "/Users/hww3/devel/pike/src/backend.cmod"
#ifndef tObjImpl_THREAD_THREAD
 /* Kludge for precompile.pike; it resolves object(Thread.Thread)
   * to tObjImpl_THREAD_THREAD, while "program_id.h" only knows about
   * tObjImpl_THREAD_ID.
   */
#define tObjImpl_THREAD_THREAD	tObjImpl_THREAD_ID
#endif /* !tObjImpl_THREAD_THREAD */

/*! @decl Thread.Thread executing_thread()
   *! @decl int executing_thread()
   *!
   *! Return the thread currently executing in the backend. I.e. the
   *! thread that has called @[`()] and hasn't exited from that call.
   *! Zero is returned if there's no thread in the backend.
   *!
   *! If Pike is compiled without thread support then @expr{1@} is
   *! returned if we're inside the backend, @expr{0@} otherwise.
   */
#define f_Backend_executing_thread_defined

#ifdef f_Backend_executing_thread_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_Backend_executing_thread_fun_num = 0;

#endif /* f_Backend_executing_thread_fun_num_used */
DEFAULT_CMOD_STORAGE void f_Backend_executing_thread(INT32 args) {
#line 2004 "/Users/hww3/devel/pike/src/backend.cmod"
if(args != 0) wrong_number_of_args_error("executing_thread",args,0);
#line 2007 "/Users/hww3/devel/pike/src/backend.cmod"
{
pop_n_elems (args);
#ifdef PIKE_THREADS
 if (THIS->exec_thread)
ref_push_object (THIS->exec_thread->thread_obj);
else
push_int (0);
#else
 push_int (THIS->exec_thread);
#endif
 }

}
/*! @decl void add_file(Stdio.File|Stdio.FILE f)
   *!
   *! Register a file to be handled by this backend.
   *! 
   *! @param f
   *!   File to register.
   *!
   *! Registers @[f] to be handled by this backend.
   *! This simply does @expr{f->set_backend(backend)@} where
   *! @expr{backend@} is this object.
   *!
   *! @seealso
   *!   @[Pike.DefaultBackend], @[main()]
   */
#define f_Backend_add_file_defined

#ifdef f_Backend_add_file_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_Backend_add_file_fun_num = 0;

#endif /* f_Backend_add_file_fun_num_used */
DEFAULT_CMOD_STORAGE void f_Backend_add_file(INT32 args) {
#line 2033 "/Users/hww3/devel/pike/src/backend.cmod"
struct object * f;
#line 2033 "/Users/hww3/devel/pike/src/backend.cmod"
if(args != 1) wrong_number_of_args_error("add_file",args,1);
#line 2033 "/Users/hww3/devel/pike/src/backend.cmod"
if(TYPEOF(Pike_sp[0-1]) != PIKE_T_OBJECT) SIMPLE_ARG_TYPE_ERROR("add_file",1,"object");
#line 2033 "/Users/hww3/devel/pike/src/backend.cmod"
debug_malloc_pass(f=Pike_sp[0-1].u.object);
{
ref_push_object (Pike_fp->current_object);
apply (f, "set_backend", 1);
pop_stack();
}


}
/*! @decl int id()
    *!
    *! Return an integer that uniquely identifies this backend. For
    *! the default backend that integer is @expr{0@}.
    */
#define f_Backend_id_defined

#ifdef f_Backend_id_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_Backend_id_fun_num = 0;

#endif /* f_Backend_id_fun_num_used */
DEFAULT_CMOD_STORAGE void f_Backend_id(INT32 args) {
#line 2046 "/Users/hww3/devel/pike/src/backend.cmod"
if(args != 0) wrong_number_of_args_error("id",args,0);
{
do { INT_TYPE ret_=((THIS->id));  push_int(ret_); return; }while(0);
#line 2049 "/Users/hww3/devel/pike/src/backend.cmod"
}

}
#define f_Backend_cq__sprintf_defined

#ifdef f_Backend_cq__sprintf_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_Backend_cq__sprintf_fun_num = 0;

#endif /* f_Backend_cq__sprintf_fun_num_used */
DEFAULT_CMOD_STORAGE void f_Backend_cq__sprintf(INT32 args) {
#line 2051 "/Users/hww3/devel/pike/src/backend.cmod"
INT_TYPE type;
#line 2051 "/Users/hww3/devel/pike/src/backend.cmod"
struct mapping * flags;
#line 2051 "/Users/hww3/devel/pike/src/backend.cmod"
if(args != 2) wrong_number_of_args_error("_sprintf",args,2);
#line 2051 "/Users/hww3/devel/pike/src/backend.cmod"
if(TYPEOF(Pike_sp[0-2]) != PIKE_T_INT) SIMPLE_ARG_TYPE_ERROR("_sprintf",1,"int");
#line 2051 "/Users/hww3/devel/pike/src/backend.cmod"
type=Pike_sp[0-2].u.integer;
#line 2051 "/Users/hww3/devel/pike/src/backend.cmod"
if(TYPEOF(Pike_sp[1-2]) != PIKE_T_MAPPING) SIMPLE_ARG_TYPE_ERROR("_sprintf",2,"mapping(mixed:mixed)");
#line 2051 "/Users/hww3/devel/pike/src/backend.cmod"
debug_malloc_pass(flags=Pike_sp[1-2].u.mapping);
{
if (type == 'O') {
push_text ("Pike.Backend(%d)");
push_int (THIS->id);
f_sprintf (2);
stack_pop_n_elems_keep_top (args);
}
else {
pop_n_elems (args);
push_int (0);
}
}

}
#line 2065 "/Users/hww3/devel/pike/src/backend.cmod"
extern int pike_make_pipe(int *);


#undef internal_gc_check_Backend_defined
#define internal_gc_check_Backend_defined

#undef Backend_event_handler_defined
#define Backend_event_handler_defined
static void gc_check_Backend_struct(void)
#line 2068 "/Users/hww3/devel/pike/src/backend.cmod"
{
struct Backend_struct *me =
(struct Backend_struct *) Pike_fp->current_storage;
int e;

for (e = 0; e < me->num_pending_calls; e++) {
if (CALL(e)->this)
debug_gc_check (CALL(e)->this,
" as call out in backend object");
}

{FOR_EACH_ACTIVE_FD_BOX (me, box) {
check_box (box, INT_MAX);
if (box->ref_obj && box->events)
debug_gc_check (box->ref_obj, " as container object "
"for an active callback in backend object");
}}
{FOR_EACH_INACTIVE_FD_BOX (me, box) {
check_box (box, INT_MAX);
if (box->ref_obj && box->events)
debug_gc_check (box->ref_obj, " as container object "
"for an inactive callback in backend object");
}}
}


#undef internal_gc_recurse_Backend_defined
#define internal_gc_recurse_Backend_defined

#undef Backend_event_handler_defined
#define Backend_event_handler_defined
static void gc_recurse_Backend_struct(void)
#line 2094 "/Users/hww3/devel/pike/src/backend.cmod"
{
struct Backend_struct *me =
(struct Backend_struct *) Pike_fp->current_storage;
int e;

for (e = 0; e < me->num_pending_calls; e++) {
if (CALL(e)->this)
gc_recurse_short_svalue ((union anything *) &CALL(e)->this, T_OBJECT);
}

{FOR_EACH_ACTIVE_FD_BOX (me, box) {
if (box->ref_obj && box->events)
gc_recurse_short_svalue ((union anything *) &box->ref_obj, T_OBJECT);
}}
{FOR_EACH_INACTIVE_FD_BOX (me, box) {
if (box->ref_obj && box->events)
gc_recurse_short_svalue ((union anything *) &box->ref_obj, T_OBJECT);
}}
}

static void low_backend_cleanup (struct Backend_struct *me)
{
me->exec_thread = 0;
}

/**
   * Generic backend setup code.
   *
   * Returns 0 if the backend needs to be polled,
   *         1 if a different thread has run the backend to completion,
   *        -1 on timeout (a different thread is running the backend,
   *           but it has not completed in time).
   */
static int low_backend_once_setup(struct Backend_struct *me,
struct timeval *start_time,
ONERROR *uwp)
{
#ifdef PIKE_DEBUG
 struct timeval max_timeout;
#endif
 struct timeval *next_timeout = &me->next_timeout, now;

alloca(0); /* Do garbage collect */
#ifdef PIKE_DEBUG
 if(d_flag > 1) do_debug();
#endif

#ifndef OWN_GETHRTIME
 ACCURATE_GETTIMEOFDAY(&now);
#else
 /* good place to run the gethrtime-conversion update
       since we have to run gettimeofday anyway /Mirar */
INACCURATE_GETTIMEOFDAY(&now);
own_gethrtime_update(&now);
#endif
 if (start_time->tv_sec < 0) {
next_timeout->tv_sec = -1;
next_timeout->tv_usec = 0;
}
else {
*next_timeout = *start_time;
my_add_timeval(next_timeout, &now);
}

if (me->wakeup_pipe_send_fd < 0) {
int pipe[2];
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: Creating wakeup pipe...\n",
THR_NO, me->id));
if(pike_make_pipe(pipe) < 0)
Pike_error("Couldn't create backend wakeup pipe! errno=%d.\n",errno);

set_nonblocking(pipe[0],1);
set_nonblocking(pipe[1],1);
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: Initializing wakeup pipe...\n",
THR_NO, me->id));
change_fd_for_box (&me->wakeup_cb_box, pipe[0]);
me->wakeup_pipe_send_fd = pipe[1];

IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: Wakeup pipe is [%d, %d]\n",
THR_NO, me->id,
me->wakeup_pipe_send_fd, THIS->wakeup_cb_box.fd));

/* Don't keep these on exec! */
set_close_on_exec(pipe[0], 1);
set_close_on_exec(pipe[1], 1);
}

*start_time = now;

if(me->exec_thread) {
#ifdef PIKE_THREADS
 if (me->exec_thread != Pike_interpreter.thread_state) {
/* The backend is busy in some other thread.
	 *
	 * It will wake us up with a cond-signal when it is done.
	 */
int old_done_counter = me->done_counter;
SWAP_OUT_CURRENT_THREAD();
if (next_timeout->tv_sec < 0) {
co_wait_interpreter(&me->backend_signal);
} else {
co_wait_interpreter_timeout(&me->backend_signal,
next_timeout->tv_sec,
next_timeout->tv_usec * 1000);
}
SWAP_IN_CURRENT_THREAD();
if (me->done_counter == old_done_counter) {
return -1;
}
return 1;
} else
#endif
 {
/* It's actually not a problem to make this function
	 * reentrant, but that'd introduce a risk of races in the
	 * callbacks (i.e. between when a read callback is called
	 * and when it reads the data), and besides I can't think
	 * of any sane way to use it. Also, this error can help
	 * discover otherwise tricky bugs. /mast */
#ifndef BACKEND_USES_CFRUNLOOP
 Pike_error ("Backend already running - cannot reenter.\n");
#else
 ; /* Do nothing, as we can call setup more than once. */
#endif
 }
}
#ifdef PIKE_THREADS
 me->exec_thread = Pike_interpreter.thread_state;
#else
 me->exec_thread = 1;
#endif

LOW_SET_ONERROR(uwp, low_backend_cleanup, me);

/* Call outs */
if(me->num_pending_calls)
if(next_timeout->tv_sec < 0 ||
my_timercmp(& CALL(0)->tv, < , next_timeout))
*next_timeout = CALL(0)->tv;

#ifdef PIKE_DEBUG
 max_timeout = *next_timeout;
#endif
 call_callback(& me->backend_callbacks, me);
#ifdef PIKE_DEBUG
 if (max_timeout.tv_sec >= 0 &&
(next_timeout->tv_sec < 0 ||
my_timercmp (&max_timeout, <, next_timeout)))
Pike_fatal ("Timeout raised from %lu.%lu to %lu.%lu "
"by a backend callback.\n",
(unsigned long)max_timeout.tv_sec,
(unsigned long)max_timeout.tv_usec,
(unsigned long)next_timeout->tv_sec,
(unsigned long)next_timeout->tv_usec);
#endif

if (next_timeout->tv_sec < 0) {
/* Wait "forever". */
next_timeout->tv_sec = 100000000;
next_timeout->tv_usec = 0;
}
else if(my_timercmp(next_timeout, > , &now))
{
my_subtract_timeval(next_timeout, &now);
}else{
next_timeout->tv_usec = 0;
next_timeout->tv_sec = 0;
}

return 0;
}


/* Call callbacks for the active events.
   *
   * NOTE: The first element in the fd_list is a sentinel!
   *
   * returns 1 on early exit.
   */
static int backend_call_active_callbacks(struct fd_callback_box *fd_list,
struct Backend_struct *PDUNUSED(me))
{
struct fd_callback_box *box;
while((box = fd_list->next))
{
int fd = box->fd;
ONERROR uwp;

/* Unhook the box. */
fd_list->next = box->next;
box->next = NULL;
SET_ONERROR(uwp, do_free_fd_box, box);

IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: Examining box for fd %d"
" revents:0x%04x\n",
THR_NO, me->id, fd, box->revents));

if (box->fd < 0) {
/* The box is no longer active.
	 * Or we have found our sentinel fd_list.
	 *
	 * Note that the loop will terminate, since we
	 * have broken the cycle above when we set
	 * box->next to NULL.
	 */
CALL_AND_UNSET_ONERROR(uwp);
continue;
}

/* From the roxen-chat re: connecttest.pike/FreeBSD:
       *
       * kqueue is returning the correct info:
       * {7,EVFILT_READ,EV_ADD|EV_EOF,61,0x0,0x0}.
       * errno 61 is ECONNREFUSED
       */
if (box->revents & box->events & PIKE_BIT_FD_READ_OOB) {
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: read_oob_callback(%d, %p)\n",
THR_NO, me->id, fd, box->ref_obj));
errno = 0;
if (box->callback (box, PIKE_FD_READ_OOB) == -1) {
CALL_AND_UNSET_ONERROR(uwp);
goto backend_round_done;
}
}

if (box->revents & box->events & PIKE_BIT_FD_READ) {
/* FIXME: Consider utilizing ACTIVE_POLLSET[i].data in
	 *        the kqueue case.
	 */
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: read_callback(%d, %p)\n",
THR_NO, me->id, fd, box->ref_obj));
errno = 0;
if (box->callback (box, PIKE_FD_READ) == -1) {
CALL_AND_UNSET_ONERROR(uwp);
goto backend_round_done;
}
}

if (box->revents & box->events & PIKE_BIT_FD_WRITE_OOB) {
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: write_oob_callback(%d, %p)\n",
THR_NO, me->id, fd, box->ref_obj));
errno = 0;
if (box->callback (box, PIKE_FD_WRITE_OOB) == -1) {
CALL_AND_UNSET_ONERROR(uwp);
goto backend_round_done;
}
}

if (box->revents & box->events & PIKE_BIT_FD_WRITE) {
/* FIXME: Consider utilizing ACTIVE_POLLSET[i].data in
	 *        the kqueue case.
	 */
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: write_callback(%d, %p)\n",
THR_NO, me->id, fd, box->ref_obj));
errno = 0;
if (box->callback (box, PIKE_FD_WRITE) == -1) {
CALL_AND_UNSET_ONERROR(uwp);
goto backend_round_done;
}
}


if (box->revents & box->events & PIKE_BIT_FD_FS_EVENT) {
/* FIXME: Consider utilizing ACTIVE_POLLSET[i].data in
	 *        the kqueue case.
	 */
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: fs_event_callback(%d, %p)\n",
THR_NO, me->id, fd, box->ref_obj));
errno = 0;
if (box->callback (box, PIKE_FD_FS_EVENT) == -1) {
CALL_AND_UNSET_ONERROR(uwp);
goto backend_round_done;
}
}

if (box->revents & PIKE_BIT_FD_ERROR) {
/* Error */
int old_events;
int err;
ACCEPT_SIZE_T len = sizeof (err);
errno = 0;
/* FIXME: This could be too late - the error might be
	 * clobbered by the callbacks we might have called
	 * above. */
if (!getsockopt (fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len)) {
IF_PD (fprintf (stderr,
"[%d]BACKEND[%d]: POLLERR on %d, error=%d\n",
THR_NO, me->id, fd, err));
errno = err;
}
else {
/* Note: This happens for FIFOs and PIPEs on Linux on the write-end
	   *       if the read-end has been closed.
	   */
#ifdef PIKE_DEBUG
#ifdef ENOTSOCK
 if (errno != ENOTSOCK) {
#endif
 fprintf(stderr,
"Got POLLERR on non-socket fd %d (getsockopt errno=%d)\n",
fd, errno);
#ifdef ENOTSOCK
 } else {
IF_PD(fprintf(stderr, "Got POLLERR on non-socket fd %d\n", fd));
}
#endif
#endif /* PIKE_DEBUG */
 errno = err = EPIPE;
}

box->revents = 0;
box->rflags = 0;

/* We don't want to keep this fd anymore.
	 * Note: This disables any further callbacks.
	 */
old_events = box->events;
set_fd_callback_events(box, box->events & PIKE_BIT_FD_ERROR,
box->flags);
if (WANT_EVENT (box, ERROR)) {
IF_PD(fprintf(stderr,
"[%d]BACKEND[%d]: error event on fd %d sent to %p\n",
THR_NO, me->id, fd, box->ref_obj));
if (box->callback (box, PIKE_FD_ERROR) == -1) {
CALL_AND_UNSET_ONERROR(uwp);
goto backend_round_done;
}
}
/* The following is temporary compat stuff. */
/* kqueue TODO: Shouldn't need to do anything here for fs events,
	 *              but should verify this.
	 */
else if (old_events & PIKE_BIT_FD_READ) {
IF_PD(fprintf(stderr,
"[%d]BACKEND[%d]: read_callback(%d, %p) for error %d\n",
THR_NO, me->id, fd, box->ref_obj, err));
if (box->callback (box, PIKE_FD_READ) == -1) {
CALL_AND_UNSET_ONERROR(uwp);
goto backend_round_done;
}
} else if (old_events & PIKE_BIT_FD_WRITE) {
IF_PD(fprintf(stderr,
"[%d]BACKEND[%d]: write_callback(%d, %p) for error %d\n",
THR_NO, me->id, fd, box->ref_obj, err));
if (box->callback (box, PIKE_FD_WRITE) == -1) {
CALL_AND_UNSET_ONERROR(uwp);
goto backend_round_done;
}
}
}

CALL_AND_UNSET_ONERROR(uwp);
}
return 0;

backend_round_done:
return 1;
}


#undef internal_init_Backend_defined
#define internal_init_Backend_defined

#undef Backend_event_handler_defined
#define Backend_event_handler_defined
static void init_Backend_struct(void)
#line 2454 "/Users/hww3/devel/pike/src/backend.cmod"
{
struct Backend_struct *me = THIS;

me->id = unused_id++;

IF_PD (fprintf (stderr, "[%d]BACKEND[%d]: init\n", THR_NO, me->id));

#ifdef _REENTRANT
 me->set_busy = 0;
co_init(&me->set_change);
#endif /* _REENTRANT */
 me->exec_thread = 0;
#ifdef PIKE_THREADS
 co_init(&me->backend_signal);
me->done_counter = 0;
#endif

me->backend_callbacks.callbacks=0;
me->backend_callbacks.num_calls=0;

INVALIDATE_CURRENT_TIME(); /* Why? /mast */

me->num_pending_calls=0;
me->call_heap = 0;
me->call_heap_size = 0;
me->hash_size=0;
me->hash_order=5;
me->call_hash=0;

me->backend_obj = Pike_fp->current_object; /* Note: Not refcounted. */

#ifdef PIKE_DEBUG
 me->inside_call_out=0;
#endif

me->fd_boxes=0;
me->fd_boxes_start = me->fd_boxes_size = 0;
me->inactive_boxes = me->free_inactive_box = NULL;
me->inactive_boxes_size = 0;

#ifdef PIKE_DEBUG
 me->debug_handler = NULL;
#endif
 me->update_fd_set_handler = NULL;
me->handler_data = me;

/* Note that we can't hook the wakeup pipe
     * until we are fully initialized.
     * The actual hooking of the wakeup pipe
     * is therefore done in create() below.
     */
me->wakeup_pipe_send_fd = -1;
INIT_FD_CALLBACK_BOX(&me->wakeup_cb_box, me, NULL, -1,
PIKE_BIT_FD_READ, wakeup_callback, 0);

me->may_need_wakeup = 0;

#ifdef DO_PIKE_CLEANUP
 num_active_backends++;
#endif
 }


#undef internal_exit_Backend_defined
#define internal_exit_Backend_defined

#undef Backend_event_handler_defined
#define Backend_event_handler_defined
static void exit_Backend_struct(void)
#line 2518 "/Users/hww3/devel/pike/src/backend.cmod"
{
struct Backend_struct *me=THIS;
int e;

IF_PD (fprintf (stderr, "[%d]BACKEND[%d]: exit\n", THR_NO, me->id));

free_callback_list(& THIS->backend_callbacks);

if (THIS->wakeup_cb_box.fd >= 0)
fd_close(THIS->wakeup_cb_box.fd);
if (me->wakeup_pipe_send_fd >= 0)
fd_close(THIS->wakeup_pipe_send_fd);

if (me->fd_boxes) {
FOR_EACH_ACTIVE_FD_BOX (me, box) {
check_box (box, INT_MAX);

#ifdef PIKE_DEBUG
 if (get_backend_for_fd (box->fd) != me)
Pike_fatal ("Inconsistency in global fd map for fd %d: "
"backend is %p, expected %p.\n",
box->fd, get_backend_for_fd (box->fd), me);
#endif

if (box->callback == compat_box_dispatcher) {
#ifdef PIKE_DEBUG
 fprintf (stderr, "[%d]BACKEND[%d]: "
"Compat callbacks left at exit for fd %d: 0x%x\n",
THR_NO, me->id, box->fd, box->events);
#endif
 really_free_compat_cb_box ((struct compat_cb_box *) box);
}

unhook_fd_callback_box(box);
}

free(me->fd_boxes);
me->fd_boxes = NULL;
me->fd_boxes_start = me->fd_boxes_size = 0;
}

if (me->inactive_boxes) {
FOR_EACH_INACTIVE_FD_BOX (me, box) {
check_box (box, INT_MAX);
#ifdef PIKE_DEBUG
 if (box->callback == compat_box_dispatcher)
Pike_fatal ("Got inactive callback in compat interface.\n");
#endif

unhook_fd_callback_box(box);
}

free(me->inactive_boxes);
me->inactive_boxes = me->free_inactive_box = NULL;
me->inactive_boxes_size = 0;
}

/* Make sure we aren't referenced any more. */
/* FIXME: Ought to keep better track of our fds so that we don't
     * need to do this loop. /mast */
for (e = 0; e < fd_map_size; e++) {
if (fd_map[e] == me) fd_map[e] = NULL;
}

/* CALL OUT */
backend_verify_call_outs(me);
for(e=0;e<me->num_pending_calls;e++)
{
CALL(e)->pos = -1;
if (CALL(e)->this)
free_object(CALL(e)->this);
}
me->num_pending_calls=0;
if(me->call_heap) free(me->call_heap);
me->call_heap = NULL;
if(me->call_hash) free(me->call_hash);
me->call_hash=NULL;

#ifdef PIKE_THREADS
 co_destroy(&me->backend_signal);
#endif
#ifdef _REENTRANT
 co_destroy(&me->set_change);
#endif

#ifdef DO_PIKE_CLEANUP
 if (!--num_active_backends) backend_cleanup();
#endif
 }

/*! @decl void create()
   */
#define f_Backend_create_defined

#ifdef f_Backend_create_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_Backend_create_fun_num = 0;

#endif /* f_Backend_create_fun_num_used */
DEFAULT_CMOD_STORAGE void f_Backend_create(INT32 args) {
#line 2610 "/Users/hww3/devel/pike/src/backend.cmod"
if(args != 0) wrong_number_of_args_error("create",args,0);
#line 2612 "/Users/hww3/devel/pike/src/backend.cmod"
{
struct Backend_struct *me = THIS;

if (!me->update_fd_set_handler) {
Pike_error("Attempt to clone the base Backend class.\n");
}


}
}

#ifdef Backend_event_handler_defined
static void Backend_event_handler(int ev) {
  switch(ev) {

#ifdef internal_gc_check_Backend_defined
  case PROG_EVENT_GC_CHECK: gc_check_Backend_struct(); break;

#endif /* internal_gc_check_Backend_defined */

#ifdef internal_gc_recurse_Backend_defined
  case PROG_EVENT_GC_RECURSE: gc_recurse_Backend_struct(); break;

#endif /* internal_gc_recurse_Backend_defined */

#ifdef internal_init_Backend_defined
  case PROG_EVENT_INIT: init_Backend_struct(); break;

#endif /* internal_init_Backend_defined */

#ifdef internal_exit_Backend_defined
  case PROG_EVENT_EXIT: exit_Backend_struct(); break;

#endif /* internal_exit_Backend_defined */
  default: break; 
  }
}

#endif /* Backend_event_handler_defined */
/*! @endclass
 */

#line 2626 "/Users/hww3/devel/pike/src/backend.cmod"
/*
 * POLL/SELECT selection
 */

#ifndef HAVE_AND_USE_POLL
/* Various BSDs have simulated poll(2) APIs. */
#undef HAVE_POLL
#endif

/* #undef BACKEND_USES_DEVPOLL */
/* #undef BACKEND_USES_DEVEPOLL */
/* #undef BACKEND_USES_POLL_DEVICE */

#ifdef HAVE_POLL

/*
 * Backends using poll(2) or similar.
 */

/* Some constants... */

/* Notes on POLLRDNORM and POLLIN:
 *
 * According to the AIX manual, POLLIN and POLLRDNORM are both set
 * if there's a nonpriority message on the read queue. POLLIN is
 * also set if the message is of 0 length.
 */

#ifndef POLLRDNORM
#define POLLRDNORM	POLLIN
#endif /* !POLLRDNORM */

#ifndef POLLRDBAND
#define POLLRDBAND	POLLPRI
#endif /* !POLLRDBAND */

#ifndef POLLWRNORM
#define POLLWRNORM	POLLOUT
#endif /* POLLWRNORM */

#ifndef POLLWRBAND
#define POLLWRBAND	POLLOUT
#endif /* !POLLWRBAND */

#define MY_POLLIN POLLRDNORM|POLLIN
#define MY_POLLOUT POLLWRNORM|POLLOUT

#define MY_POLLEXCEPT	POLLRDBAND|POLLRDNORM|POLLIN
#define MY_POLLRDBAND	POLLRDBAND|POLLPRI
#define MY_POLLWREXCEPT	POLLWRBAND|POLLWRNORM|POLLOUT
#define MY_POLLWRBAND	POLLWRBAND|MY_POLLOUT
#define MY_POLLNVAL	POLLNVAL

#if (POLLRDBAND != POLLRDNORM) && (POLLRDBAND != POLLIN)
#define RDBAND_IS_SPECIAL
#endif

#if (POLLWRBAND != POLLOUT) && (POLLWRBAND != POLLWRNORM)
#define WRBAND_IS_SPECIAL
#endif

#define TIMEOUT_IS_MILLISECONDS

#ifdef BACKEND_USES_DEVPOLL
/*
 * Backend using /dev/poll-style poll device.
 *
 * Used on:
 *   Solaris 7 + patches and above.
 *   OSF/1 + patches and above.
 *   IRIX 5.6.15m and above.
 */

#define POLL_EVENT	struct pollfd
#define OPEN_POLL_DEVICE(X)	open(PIKE_POLL_DEVICE, O_RDWR)
#define CHILD_NEEDS_TO_REOPEN

#define DECLARE_POLL_EXTRAS		\
  POLL_EVENT poll_fds[POLL_SET_SIZE];	\
  struct dvpoll poll_request = {	\
    poll_fds,				\
    POLL_SET_SIZE,			\
    0,					\
  }

#define PDB_POLL(PFD, TIMEOUT)					\
  ((poll_request.dp_timeout = (TIMEOUT)),			\
   (ioctl(PFD, DP_POLL, &poll_request, sizeof(poll_request))))

int POLL_DEVICE_SET_EVENTS(struct Backend_struct *me,
int pfd, int fd, INT32 events)
{
struct pollfd poll_state[2];
int e;
int sz = sizeof(poll_state);

IF_PD(fprintf(stderr, "POLL_DEVICE_SET_EVENTS(%p, %d, %d, 0x%08x)\n",
me, pfd, fd, events));

/* NOTE: POLLREMOVE must (unfortunately) be a separate request. */
poll_state[0].fd = fd;
poll_state[0].events = POLLREMOVE;
poll_state[0].revents = 0;
poll_state[1].fd = fd;
poll_state[1].events = events;
poll_state[1].revents = 0;

if (!events) {
/* We're not interrested in the fd anymore. */
sz = sizeof(poll_state[0]);
}

#ifdef _REENTRANT
 /* FIXME: Ought to check if we're the backend.
   */
if(num_threads>1)
{
SWAP_OUT_CURRENT_THREAD();
/* Release the poll set from the backend. */
IF_PD(fprintf(stderr, "POLL_DEVICE_SET_EVENTS[%p] grabbing the poll set\n",
me));
while (me->set_busy) {
co_wait_interpreter(&me->set_change);
}
me->set_busy = 1;
IF_PD(fprintf(stderr, "POLL_DEVICE_SET_EVENTS[%p] wake up backend\n",
me));
backend_wake_up_backend(me);
/* The backend is now waiting in wakeup_callback(). */
SWAP_IN_CURRENT_THREAD();
}
#endif /* _REENTRANT */

IF_PD(fprintf(stderr, "POLL_DEVICE_SET_EVENTS[%p] updating the poll set\n",
me));
while (((e = write(pfd, poll_state, sz)) < 0) && (errno == EINTR))
;

#ifdef _REENTRANT
 me->set_busy = 0;
if(num_threads>1)
{
/* Release the backend from wakeup_callback(). */
IF_PD(fprintf(stderr, "POLL_DEVICE_SET_EVENTS[%p] releasing the backend\n",
me));
co_broadcast(&me->set_change);
}
#endif /* _REENTRANT */

if (e < 0) {
Pike_fatal("Failed to set state for fd %d in " PIKE_POLL_DEVICE
" (errno:%d).\n",
fd, errno);
}

/* FIXME: Probably ought to support partial writes. */
if (e != sz) {
Pike_fatal("Failed to set state for fd %d in " PIKE_POLL_DEVICE
" short write (%d != %d).\n",
fd, e, (int)sizeof(poll_state));
}
IF_PD(fprintf(stderr, "POLL_DEVICE_SET_EVENTS[%p] ==> %d\n",
me, e));
return e;
}

#elif defined(BACKEND_USES_DEVEPOLL)
/*
 * Backend using /dev/epoll-style poll device.
 *
 * Used on:
 *   Linux 2.6 and above.
 * Note:
 *   Some libc's are missing wrappers for the system calls, so
 *   we include the appropriate wrappers below.
 */

#ifndef PIKE_POLL_DEVICE
#define PIKE_POLL_DEVICE	"epoll"
#endif

/* The following three are defined by <gnu/stubs.h> which is included
 * from <features.h> which is included from just about everywhere, so
 * it is safe to assume that they have been defined if appropriate.
 */
#if defined(__stub_epoll_create) || defined(__stub_epoll_ctl) || \
    defined(__stub_epoll_wait)
/* We have a libc without the wrappers for epoll support.
 */
#ifndef __NR_epoll_create
/* Our libc doesn't even know the syscall numbers for the epoll syscalls.
 */
#ifdef __i386__
#define __NR_epoll_create 254
#define __NR_epoll_ctl 255
#define __NR_epoll_wait 256
#elif defined(__ia64__)
#define __NR_epoll_create 1243
#define __NR_epoll_ctl 1244
#define __NR_epoll_wait 1245
#elif defined(__x86_64__)
#define __NR_epoll_create 214
#define __NR_epoll_ctl 233
#define __NR_epoll_wait 232
#else /* cpu types */
#error Syscall numbers for epoll_create et al not known on this architecture.
#endif /* cpu types */
#endif /* !defined(__NR_epoll_create) */
#if defined(_syscall1) && defined(_syscall4)
_syscall1(int, epoll_create, int, size); 
_syscall4(int, epoll_ctl, int, epfd, int, op, int, fd,
struct epoll_event *, event);
_syscall4(int, epoll_wait, int, epfd, struct epoll_event *, pevents,
int, maxevents, int, timeout);
#undef __stub_epoll_create
#undef __stub_epoll_ctl
#undef __stub_epoll_wait
#else /* !_syscall1 || !_syscall4 */
#error Missing macros for generation of syscall wrappers.
#endif /* _syscall1 && _syscall4 */
#endif /* __stub_epoll_{create, ctl, wait} */

#define POLL_EVENT	struct epoll_event
#define PDB_GET_FD(EVENT)	EVENT.data.fd
#define PDB_GET_EVENTS(EVENT)	EVENT.events

/* FIXME: Might want another value instead on POLL_SET_SIZE. */
#define OPEN_POLL_DEVICE(X)	epoll_create(POLL_SET_SIZE)

#define DECLARE_POLL_EXTRAS		\
  POLL_EVENT poll_fds[POLL_SET_SIZE]

#define PDB_POLL(PFD, TIMEOUT)				\
  epoll_wait(PFD, poll_fds, POLL_SET_SIZE, TIMEOUT)

int POLL_DEVICE_SET_EVENTS(struct Backend_struct *UNUSED(me),
int pfd, int fd, INT32 events)
{
int e;

if (events) {
struct epoll_event ev;
#ifdef __CHECKER__
 memset(&ev, 0, sizeof(ev));
#endif
 ev.events = events;
ev.data.fd = fd;

/* To avoid valgrind complaints when fd doesn't fill up the
     * ev.data union. */
PIKE_MEM_RW (ev.data);

/* The /dev/epoll interface exposes kernel implementation details...
     */
IF_PD(fprintf(stderr, "epoll_ctl(%d, EPOLL_CTL_MOD, %d, { 0x%08x, %d })\n",
pfd, fd, events, fd));
while (((e = epoll_ctl(pfd, EPOLL_CTL_MOD, fd, &ev)) < 0) &&
(errno == EINTR))
;
if ((e < 0) && (errno == ENOENT)) {
IF_PD(fprintf(stderr,
"epoll_ctl(%d, EPOLL_CTL_ADD, %d, { 0x%08x, %d })\n",
pfd, fd, events, fd));
while (((e = epoll_ctl(pfd, EPOLL_CTL_ADD, fd, &ev)) < 0) &&
(errno == EINTR))
;
}
} else {
struct epoll_event dummy;
/* The last argument must be a proper struct pointer even
     * though it isn't used...
     */
PIKE_MEM_RW (dummy);
IF_PD(fprintf(stderr, "epoll_ctl(%d, EPOLL_CTL_DEL, %d, &dummy)\n",
pfd, fd));
while (((e = epoll_ctl(pfd, EPOLL_CTL_DEL, fd, &dummy)) < 0) &&
(errno == EINTR))
;
if ((e < 0) && (errno == ENOENT)) return 0;
}
IF_PD(if (e < 0) {
fprintf(stderr, "epoll_ctl() failed with errno: %d\n", errno);
});

return e;
}

#endif /* HAVE_SYS_DEVPOLL_H || HAVE_SYS_EPOLL_H */

#ifdef HAVE_POLL

/*
 * Backend using poll(2).
 *
 * This is used on most older SVR4- or POSIX-style systems.
 */

#define PB_POLL(SET, TIMEOUT)				\
  poll((SET).poll_fds, (SET).num_in_poll, (TIMEOUT))

struct pb_selectors
{
struct pollfd *poll_fds;
int poll_fd_size;
int num_in_poll;
};

static void pb_MY_FD_SET(struct pb_selectors *me, int fd, int add)
{
int i;
IF_PD(fprintf(stderr, "BACKEND: MY_FD_SET(%d, 0x%04x)\n", fd, add));
for(i=0; i<me->num_in_poll; i++)
{
if(me->poll_fds[i].fd == fd)
{
me->poll_fds[i].events |= add;
return;
}
}
me->num_in_poll++;
if (me->num_in_poll > me->poll_fd_size)
{
me->poll_fd_size += me->num_in_poll; /* Usually a doubling */
if (me->poll_fds) {
me->poll_fds =
realloc(me->poll_fds, sizeof(struct pollfd)*me->poll_fd_size);
} else {
me->poll_fds = malloc(sizeof(struct pollfd)*me->poll_fd_size);
}
if (!me->poll_fds)
{
Pike_fatal("Out of memory in backend::MY_FD_SET()\n"
"Tried to allocate %d pollfds\n", me->poll_fd_size);
}
}
me->poll_fds[me->num_in_poll-1].fd = fd;
me->poll_fds[me->num_in_poll-1].events = add;
}

static void pb_MY_FD_CLR(struct pb_selectors *me, int fd, int sub)
{
int i;
IF_PD(fprintf(stderr, "BACKEND: POLL_FD_CLR(%d, 0x%04x)\n", fd, sub));
if(!me->poll_fds) return;
for(i=0; i<me->num_in_poll; i++)
{
if(me->poll_fds[i].fd == fd)
{
me->poll_fds[i].events &= ~sub;
if(!me->poll_fds[i].events)
{
/* Note that num_in_poll is decreased here.
	 * This is to avoid a lot of -1's below.
	 * /grubba
	 */
me->num_in_poll--;
if(i != me->num_in_poll)
{
me->poll_fds[i] = me->poll_fds[me->num_in_poll];
}
/* Might want to shrink poll_fds here, but probably not. */
}
break;
}
}
}


static void pb_copy_selectors(struct pb_selectors *to,
struct pb_selectors *from)
{
IF_PD(fprintf(stderr, "BACKEND: copy_poll_set() from->num_in_poll=%d\n",
from->num_in_poll));

if (to->poll_fd_size < from->num_in_poll)
{
IF_PD(fprintf(stderr, "BACKEND: copy_poll_set() size %d -> %d\n",
to->poll_fd_size,
from->poll_fd_size));
to->poll_fd_size=from->poll_fd_size;
if (to->poll_fds) {
to->poll_fds =
realloc(to->poll_fds, sizeof(struct pollfd)*to->poll_fd_size);
} else {
to->poll_fds =
malloc(sizeof(struct pollfd)*to->poll_fd_size);
}
if (!to->poll_fds) {
Pike_fatal("Out of memory in backend::copy_poll_set()\n"
"Tried to allocate %d pollfds\n", to->poll_fd_size);
}
}

memcpy(to->poll_fds,
from->poll_fds,
sizeof(struct pollfd)*from->num_in_poll);
to->num_in_poll=from->num_in_poll;
}

#endif /* HAVE_POLL */

#define PB_GET_FD(EVENT)	EVENT.fd
#ifndef PDB_GET_FD
#define PDB_GET_FD(EVENT)	PB_GET_FD(EVENT)
#endif
#define PB_GET_EVENTS(EVENT)	EVENT.revents
#ifndef PDB_GET_EVENTS
#define PDB_GET_EVENTS(EVENT)	PB_GET_EVENTS(EVENT)
#endif
#ifndef PDB_GET_FLAGS
#define PDB_GET_FLAGS(EVENT)	0
#endif

#elif defined(BACKEND_USES_KQUEUE)
/*
 * Backend using kqueue-style poll device.
 *
 * FIXME: Not fully implemented yet! Out of band data handling is missing.
 *
 * Used on
 *   FreeBSD 4.1 and above.
 *   MacOS X/Darwin 7.x and above.
 *   Various other BSDs.
 */


#define POLL_EVENT	struct kevent

#if defined(BACKEND_USES_CFRUNLOOP)
#define OPEN_POLL_DEVICE(X)	my_kqueue(X)
#else
#define OPEN_POLL_DEVICE(X)	kqueue()
#endif

#define CHILD_NEEDS_TO_REOPEN

#define PIKE_POLL_DEVICE	"kqueue"

#define TIMEOUT_IS_TIMESPEC

#define MY_POLLIN	EVFILT_READ
#define MY_POLLOUT	EVFILT_WRITE

/* NOTE: The following 4 event types are specific to kqueue(2) */
#define MY_POLLFSEVENT	EVFILT_VNODE
#define MY_POLLPROCESS	EVFILT_PROC
#define MY_POLLSIGNAL	EVFILT_SIGNAL
#define MY_POLLTIMER	EVFILT_TIMER

#define MY_POLLERR	EV_ERROR
#if 0
#define MY_POLLHUP	EV_EOF
#else /* !0 */
#define MY_POLLHUP	0
#endif /* 0 */

#ifdef __APPLE__
/* Not defined in old MacOS X. */
#ifndef EV_OOBAND
#define EV_OOBAND	EV_FLAG1
#endif
#elif !defined(EV_OOBAND)
/* FreeBSD seems to handle OOB data inline with ordinary data. */
#define EV_OOBAND	0
#endif /* __APPLE__ */

/* FIXME: The kqueue API has no documented support for out of band data. */
#define MY_POLLEXCEPT	EVFILT_READ
#define MY_POLLRDBAND	EVFILT_READ
#define MY_POLLWREXCEPT	EVFILT_WRITE
#define MY_POLLWRBAND	EVFILT_WRITE

#define DECLARE_POLL_EXTRAS		\
  POLL_EVENT poll_fds[POLL_SET_SIZE]

#define PDB_POLL(SET, TIMEOUT)					\
  kevent((SET), NULL, 0, poll_fds, POLL_SET_SIZE, &(TIMEOUT))

#define PDB_GET_FD(EVENT)		EVENT.ident
#define PDB_GET_EVENTS(EVENT)		EVENT.filter
#define PDB_GET_FLAGS(EVENT)    EVENT.fflags
#define PDB_CHECK_EVENT(EVENT, MASK)	(PDB_GET_EVENTS(EVENT) == (MASK))

/* NOTE: Error events are signalled in the flags field. They thus
 *       must be checked for before the ordinary events.
 */
#define PDB_CHECK_ERROR_EVENT(EVENT, MASK)	(EVENT.flags & (MASK))

int pdb_MY_FD_CLR(int *pfd, int fd, int filter)
{
struct kevent ev;

/* Note: Use EV_DISABLE in preference to EV_DELETE, since
   *       odds are that the fd will be reenabled, and the
   *       filter is deleted anyway when the fd is closed.
   */
EV_SET(&ev, fd, filter, EV_DISABLE, 0, 0, 0);

return kevent(*pfd, &ev, 1, NULL, 0, NULL);
}

#define pdb_MY_FD_SET(PFD, FD, FILTER) pdb_MY_FD_SET2(PFD, FD, FILTER, 0)

int pdb_MY_FD_SET2(int *pfd, int fd, int filter, int fflags)
{
struct kevent ev[2];

/* VNODE filters seem to need ONESHOT mode, else they just repeat endlessly. */
if(filter == EVFILT_VNODE)
EV_SET(ev, fd, filter, EV_ADD|EV_ENABLE|EV_CLEAR, fflags, 0, 0);
else
EV_SET(ev, fd, filter, EV_ADD|EV_ENABLE, fflags, 0, 0);

return kevent(*pfd, ev, 1, NULL, 0, NULL);
}

#define pdb_MY_FD_CLR_RDBAND(SET, FD)
#define pdb_MY_FD_CLR_WRBAND(SET, FD)

#endif

/*
 * Backend using select(2)
 *
 * This is used on most older BSD-style systems, and WIN32.
 */

#define MY_READSET	0
#define MY_WRITESET	1
#define MY_EXCEPTSET	2
/* except == incoming OOB data (or error according to POSIX)
 * outgoing OOB data is multiplexed on write
 */

struct sb_selectors
{
int max_fd;
my_fd_set sets[3];
};

struct sb_active_selectors
{
fd_set asets[3];
int max_fd;
};

#define SB_SELECT(SET, TIMEOUT)					\
  fd_select((SET).max_fd + 1,					\
	    (SET).asets + MY_READSET,				\
	    (SET).asets + MY_WRITESET,				\
	    (SET).asets + MY_EXCEPTSET,				\
	    (TIMEOUT).tv_sec >= 100000000 ? NULL : &(TIMEOUT))

void sb_MY_FD_CLR(struct sb_selectors *me, int fd, int setno)
{
if(fd > me->max_fd) return;
my_FD_CLR(fd, me->sets + setno);
if(fd == me->max_fd)
{
while(me->max_fd >=0 &&
!my_FD_ISSET(me->max_fd, me->sets + MY_READSET) &&
!my_FD_ISSET(me->max_fd, me->sets + MY_WRITESET)
&& !my_FD_ISSET(me->max_fd, me->sets + MY_EXCEPTSET)
)
me->max_fd--;
}
}

void sb_MY_FD_SET(struct sb_selectors *me, int fd, int setno)
{
my_FD_SET(fd, me->sets + setno);
if(fd > me->max_fd) me->max_fd=fd;
}

#ifndef HAVE_POLL
static void sb_copy_selectors(struct sb_active_selectors *to,
struct sb_selectors *from)
{
fd_copy_my_fd_set_to_fd_set(to->asets + MY_READSET,
from->sets + MY_READSET, from->max_fd+1);
fd_copy_my_fd_set_to_fd_set(to->asets + MY_WRITESET,
from->sets + MY_WRITESET, from->max_fd+1);
fd_copy_my_fd_set_to_fd_set(to->asets + MY_EXCEPTSET,
from->sets + MY_EXCEPTSET, from->max_fd+1);
to->max_fd=from->max_fd;
}
#endif

#ifndef POLL_SET_SIZE
#define POLL_SET_SIZE		32
#endif /* !POLL_SET_SIZE */

#define PB_CHECK_EVENT(EVENT, MASK)	(PB_GET_EVENTS(EVENT) & (MASK))
#ifndef PDB_CHECK_EVENT
#define PDB_CHECK_EVENT(EVENT, MASK)	(PDB_GET_EVENTS(EVENT) & (MASK))
#endif /* PB_CHECK_EVENT */

#define PB_CHECK_ERROR_EVENT(EVENT, MASK)	PB_CHECK_EVENT(EVENT, MASK)
#ifndef PDB_CHECK_ERROR_EVENT
#define PDB_CHECK_ERROR_EVENT(EVENT, MASK)	PDB_CHECK_EVENT(EVENT, MASK)
#endif /* PB_CHECK_ERROR_EVENT */

#ifdef RDBAND_IS_SPECIAL
#  define pb_MY_FD_CLR_RDBAND(SET, FD) pb_MY_FD_CLR (SET, FD, MY_POLLRDBAND)
#else
#  define pb_MY_FD_CLR_RDBAND(SET, FD)
#endif

#ifdef WRBAND_IS_SPECIAL
#  define pb_MY_FD_CLR_WRBAND(SET, FD) pb_MY_FD_CLR (SET, FD, MY_POLLWRBAND)
#else
#  define pb_MY_FD_CLR_WRBAND(SET, FD)
#endif

#ifndef MY_POLLERR
#define MY_POLLERR	POLLERR
#endif

#ifndef MY_POLLHUP
#define MY_POLLHUP	POLLHUP
#endif

#ifndef MY_POLLFSEVENT
#define MY_POLLFSEVENT	0
#endif

#ifndef MY_POLLSIGNAL
#define MY_POLLSIGNAL	0
#endif

#if defined(BACKEND_USES_POLL_DEVICE) || defined(BACKEND_USES_KQUEUE)

/*! @class PollDeviceBackend
 *! @inherit __Backend
 *!
 *! @[Backend] implemented with @tt{/dev/poll@} (Solaris, OSF/1 and IRIX),
 *! @tt{epoll(2)@} (Linux) or @tt{kqueue(2)@} (MacOS X, FreeBSD, OpenBSD, etc).
 *!
 *! @seealso
 *!   @[Backend]
 */

#undef class_PollDeviceBackend_defined
#define class_PollDeviceBackend_defined
DEFAULT_CMOD_STORAGE struct program *PollDeviceBackend_program=NULL;

#ifdef PollDeviceBackend_program_fun_num_used
DEFAULT_CMOD_STORAGE int PollDeviceBackend_program_fun_num=-1;
#endif /* PollDeviceBackend_program_fun_num_used */

#undef inherit_Backend_PollDeviceBackend_defined
#define inherit_Backend_PollDeviceBackend_defined
#line 3269 "/Users/hww3/devel/pike/src/backend.cmod"
static int PollDeviceBackend_Backend_inh_num = -1;
#line 3269 "/Users/hww3/devel/pike/src/backend.cmod"
static int PollDeviceBackend_Backend_inh_offset = -1;
#line 3271 "/Users/hww3/devel/pike/src/backend.cmod"
/* Helpers to find the above inherit. */
static ptrdiff_t pdb_offset = 0;

#undef var_backend_PollDeviceBackend_defined
#define var_backend_PollDeviceBackend_defined
#line 3275 "/Users/hww3/devel/pike/src/backend.cmod"
/* 
   * POLL/SELECT fd sets
   */

#undef var_set_PollDeviceBackend_defined
#define var_set_PollDeviceBackend_defined
#line 3279 "/Users/hww3/devel/pike/src/backend.cmod"
#if defined(BACKEND_USES_CFRUNLOOP)
 
#undef var_go_cf_PollDeviceBackend_defined
#define var_go_cf_PollDeviceBackend_defined

#undef var_external_run_PollDeviceBackend_defined
#define var_external_run_PollDeviceBackend_defined

#undef var_fdref_PollDeviceBackend_defined
#define var_fdref_PollDeviceBackend_defined

#undef var_source_PollDeviceBackend_defined
#define var_source_PollDeviceBackend_defined

#undef var_beObserver_PollDeviceBackend_defined
#define var_beObserver_PollDeviceBackend_defined

#undef var_beTimer_PollDeviceBackend_defined
#define var_beTimer_PollDeviceBackend_defined

#undef var_event_count_PollDeviceBackend_defined
#define var_event_count_PollDeviceBackend_defined

#undef var_gil_released_PollDeviceBackend_defined
#define var_gil_released_PollDeviceBackend_defined

#undef var_thread_state_PollDeviceBackend_defined
#define var_thread_state_PollDeviceBackend_defined
#line 3288 "/Users/hww3/devel/pike/src/backend.cmod"
/* used by external runloops. */
#endif /* BACKEND_USES_CFRUNLOOP */
#ifdef DECLARE_POLL_EXTRAS
 /* Declare any extra variables needed by MY_POLL(). */

#undef var_poll_fds_PollDeviceBackend_defined
#define var_poll_fds_PollDeviceBackend_defined
#line 3293 "/Users/hww3/devel/pike/src/backend.cmod"
#endif /* DECLARE_POLL_EXTRAS */


#undef THIS
#define THIS ((struct PollDeviceBackend_struct *)(Pike_interpreter.frame_pointer->current_storage))

#undef THIS_POLLDEVICEBACKEND
#define THIS_POLLDEVICEBACKEND ((struct PollDeviceBackend_struct *)(Pike_interpreter.frame_pointer->current_storage))

#undef OBJ2_POLLDEVICEBACKEND
#define OBJ2_POLLDEVICEBACKEND(o) ((struct PollDeviceBackend_struct *)(o->storage+PollDeviceBackend_storage_offset))

#undef GET_POLLDEVICEBACKEND_STORAGE
#define GET_POLLDEVICEBACKEND_STORAGE(o) ((struct PollDeviceBackend_struct *)(o->storage+PollDeviceBackend_storage_offset)
static ptrdiff_t PollDeviceBackend_storage_offset;
struct PollDeviceBackend_struct {

#ifdef var_backend_PollDeviceBackend_defined
#line 3273 "/Users/hww3/devel/pike/src/backend.cmod"
struct Backend_struct *backend;
#endif /* var_backend_PollDeviceBackend_defined */

#ifdef var_set_PollDeviceBackend_defined
#line 3278 "/Users/hww3/devel/pike/src/backend.cmod"
int set;
#endif /* var_set_PollDeviceBackend_defined */

#ifdef var_go_cf_PollDeviceBackend_defined
#line 3280 "/Users/hww3/devel/pike/src/backend.cmod"
int go_cf;
#endif /* var_go_cf_PollDeviceBackend_defined */

#ifdef var_external_run_PollDeviceBackend_defined
#line 3281 "/Users/hww3/devel/pike/src/backend.cmod"
int external_run;
#endif /* var_external_run_PollDeviceBackend_defined */

#ifdef var_fdref_PollDeviceBackend_defined
#line 3282 "/Users/hww3/devel/pike/src/backend.cmod"
CFFileDescriptorRef fdref;
#endif /* var_fdref_PollDeviceBackend_defined */

#ifdef var_source_PollDeviceBackend_defined
#line 3283 "/Users/hww3/devel/pike/src/backend.cmod"
CFRunLoopSourceRef source;
#endif /* var_source_PollDeviceBackend_defined */

#ifdef var_beObserver_PollDeviceBackend_defined
#line 3284 "/Users/hww3/devel/pike/src/backend.cmod"
CFRunLoopObserverRef beObserver;
#endif /* var_beObserver_PollDeviceBackend_defined */

#ifdef var_beTimer_PollDeviceBackend_defined
#line 3285 "/Users/hww3/devel/pike/src/backend.cmod"
CFRunLoopTimerRef beTimer;
#endif /* var_beTimer_PollDeviceBackend_defined */

#ifdef var_event_count_PollDeviceBackend_defined
#line 3286 "/Users/hww3/devel/pike/src/backend.cmod"
int event_count;
#endif /* var_event_count_PollDeviceBackend_defined */

#ifdef var_gil_released_PollDeviceBackend_defined
#line 3287 "/Users/hww3/devel/pike/src/backend.cmod"
int gil_released;
#endif /* var_gil_released_PollDeviceBackend_defined */

#ifdef var_thread_state_PollDeviceBackend_defined
#line 3288 "/Users/hww3/devel/pike/src/backend.cmod"
struct thread_state * thread_state;
#endif /* var_thread_state_PollDeviceBackend_defined */

#ifdef var_poll_fds_PollDeviceBackend_defined
struct kevent* poll_fds;
#endif /* var_poll_fds_PollDeviceBackend_defined */
};
#ifdef PIKE_DEBUG
/* Ensure the struct is used in a variable declaration, or else gdb might not see it. */
static struct PollDeviceBackend_struct *PollDeviceBackend_gdb_dummy_ptr;
#endif
/*! @decl optional void set_signal_event_callback(int signum, function cb)
   *!
   *! Request @[cb] to be called from the backend when the signal
   *! @[signum] is received.
   *!
   *! @note
   *!   This function is a noop except for the @tt{kqueue@} case.
   *!
   *! @note
   *!   Caveat emptor: Unlikely to work.
   *!
   *! @seealso
   *!   @[signal()]
   */
#define f_PollDeviceBackend_set_signal_event_callback_defined

#ifdef f_PollDeviceBackend_set_signal_event_callback_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_PollDeviceBackend_set_signal_event_callback_fun_num = 0;

#endif /* f_PollDeviceBackend_set_signal_event_callback_fun_num_used */
DEFAULT_CMOD_STORAGE void f_PollDeviceBackend_set_signal_event_callback(INT32 args) {
#line 3311 "/Users/hww3/devel/pike/src/backend.cmod"
INT_TYPE signum;
#line 3311 "/Users/hww3/devel/pike/src/backend.cmod"
struct svalue * cb;
#line 3311 "/Users/hww3/devel/pike/src/backend.cmod"
if(args != 2) wrong_number_of_args_error("set_signal_event_callback",args,2);
#line 3311 "/Users/hww3/devel/pike/src/backend.cmod"
if(TYPEOF(Pike_sp[0-2]) != PIKE_T_INT) SIMPLE_ARG_TYPE_ERROR("set_signal_event_callback",1,"int");
#line 3311 "/Users/hww3/devel/pike/src/backend.cmod"
signum=Pike_sp[0-2].u.integer;
#line 3311 "/Users/hww3/devel/pike/src/backend.cmod"
if(TYPEOF(Pike_sp[1-2]) != PIKE_T_FUNCTION) SIMPLE_ARG_TYPE_ERROR("set_signal_event_callback",2,"function");
#line 3311 "/Users/hww3/devel/pike/src/backend.cmod"
cb=Pike_sp+1-2; dmalloc_touch_svalue(Pike_sp+1-2);
#line 3313 "/Users/hww3/devel/pike/src/backend.cmod"
{
int q;
#ifdef BACKEND_USES_KQUEUE
 struct kevent ev[2];
EV_SET(ev, signum, MY_POLLSIGNAL, EV_ADD, 0, 0, 0);
q = kevent(THIS->set, ev, 1, NULL, 0, NULL);

/* FIXME: Shouldn't cb be registered somewhere? */
#endif
 pop_n_elems(args);
}

}
#line 3325 "/Users/hww3/devel/pike/src/backend.cmod"
/*
   * FD set handling
   */

static void pdb_UPDATE_BLACK_BOX(struct PollDeviceBackend_struct *me, int fd,
int wanted_events)
{
#ifdef BACKEND_USES_POLL_DEVICE
 INT32 events = 0;

if (wanted_events & PIKE_BIT_FD_READ) {
events |= MY_POLLIN;
}
if (wanted_events & PIKE_BIT_FD_WRITE) {
events |= MY_POLLOUT;
}
if (wanted_events & PIKE_BIT_FD_READ_OOB) {
events |= MY_POLLRDBAND;
}
if (wanted_events & PIKE_BIT_FD_WRITE_OOB) {
events |= MY_POLLWRBAND;
}
if (wanted_events & PIKE_BIT_FD_FS_EVENT) {
events |= MY_POLLFSEVENT;
}

IF_PD(fprintf(stderr, "UPDATE_BLACK_BOX(%d, %d) ==> events: 0x%08x\n",
me->set, fd, events));
POLL_DEVICE_SET_EVENTS(me->backend, me->set, fd, events);
#elif defined(BACKEND_USES_KQUEUE)
 /* Note: Only used by REOPEN_POLL_DEVICE on a freshly opened kqueue. */
struct kevent ev[3];
int nev = 0;
if (wanted_events & (PIKE_BIT_FD_READ|PIKE_BIT_FD_READ_OOB)) {
if (wanted_events & PIKE_BIT_FD_READ_OOB) {
/* We want OOB notifications.
	 *
	 * Without setting EV_OOBAND, we won't get any OOB notifications,
	 * unless there is also in-band data.
	 */
IF_PD(fprintf(stderr, "BACKEND: EV_SET fd:%d, READ, ADD, [OOBAND]\n",
fd));
EV_SET(ev, fd, MY_POLLIN, EV_ADD|EV_OOBAND, 0, 0, 0);
} else {
IF_PD(fprintf(stderr, "BACKEND: EV_SET fd:%d, READ, ADD\n", fd));
EV_SET(ev, fd, MY_POLLIN, EV_ADD, 0, 0, 0);
}
nev++;
}
if (wanted_events & PIKE_BIT_FD_WRITE ||
wanted_events & PIKE_BIT_FD_WRITE_OOB) {
IF_PD(fprintf(stderr, "BACKEND: EV_SET fd:%d, WRITE, ADD\n", fd));
EV_SET(ev+nev, fd, MY_POLLOUT, EV_ADD, 0, 0, 0);
nev++;
}
if (wanted_events & PIKE_BIT_FD_FS_EVENT) {
/* kqueue TODO generate fflags from the high bits of
       *             the wanted_events argument.
       */
EV_SET(ev+nev, fd, MY_POLLFSEVENT, EV_ADD, 0, 0, 0);
nev++;
}
if (nev)
kevent(me->set, ev, nev, NULL, 0, NULL);
#endif /* BACKEND_USES_POLL_DEVICE */
 }


#if defined(BACKEND_USES_CFRUNLOOP)
 /* We place these declarations here rather than at the top
   * in order to avoid struct-y unpleasantness
   */
static int init_cf(struct PollDeviceBackend_struct *me, int i);
static int init_external_cfrl(struct PollDeviceBackend_struct *me, int i);
static int low_my_kqueue(struct PollDeviceBackend_struct *me);

static int my_kqueue(struct PollDeviceBackend_struct *me)
{
int i;

i = low_my_kqueue(me);

return i;
}

static int low_my_kqueue(struct PollDeviceBackend_struct *me)
{
int i;

i = kqueue();
if(me->go_cf)
return init_cf(me, i);
else return i;
}

/* arg i is the kqueue. */
static int init_external_cfrl(struct PollDeviceBackend_struct *me,
int UNUSED(i))
{
/* we assume that init_cf() has already been called. */

CFRunLoopObserverRef beObserver = NULL;

int myActivities = kCFRunLoopBeforeWaiting | kCFRunLoopAfterWaiting |
kCFRunLoopBeforeTimers | kCFRunLoopBeforeSources | kCFRunLoopExit;

CFRunLoopObserverContext context = {0, me, NULL, NULL, NULL};

beObserver = CFRunLoopObserverCreate(NULL, myActivities, 1,
/* repeat */ 1, cfObserverCallback, &context);

if (beObserver)
{
CFRetain(beObserver);
CFRunLoopAddObserver(CFRunLoopGetCurrent(), beObserver,
kCFRunLoopDefaultMode);
}

return 0;
}

/* arg i is the kqueue. */
static int exit_external_cfrl(struct PollDeviceBackend_struct *me)
{
/* we assume that init_cf() has already been called. */
CFRunLoopObserverRef beObserver = me->beObserver;
CFRunLoopTimerRef beTimer = me->beTimer; 
if (beObserver)
{
CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), beObserver,
kCFRunLoopDefaultMode);
CFRelease(beObserver);
} 
if(beTimer)
{
CFRelease(beTimer);
}

return 0;
}

/* arg i is the kqueue. */
static int init_cf(struct PollDeviceBackend_struct *me, int i)
{
CFFileDescriptorContext context = {0, me, NULL, NULL, NULL};

me->fdref = CFFileDescriptorCreate(kCFAllocatorDefault, i, true,
noteEvents, &context);
CFRetain(me->fdref);

me->source = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault,
me->fdref, 0);
CFFileDescriptorEnableCallBacks(me->fdref, kCFFileDescriptorReadCallBack); 
CFRetain(me->source);

return i;
}

static void exit_cf(struct PollDeviceBackend_struct *me)
{
if(me->source)
{
CFRunLoopSourceInvalidate(me->source);
CFRelease(me->source);
}

if(me->fdref)
CFRelease(me->fdref);
}

#endif /* BACKEND_USES_CFRUNLOOP */

/* This is called in the child process to restore
   * poll state after fork() in case of detaching.
   */
static void pdb_REOPEN_POLL_DEVICE(struct PollDeviceBackend_struct *me)
{
int fd;
while ((close(me->set) < 0) && (errno == EINTR))
;
while (((fd = OPEN_POLL_DEVICE(me)) < 0) && (errno == EINTR))
;
if (fd < 0) {
Pike_fatal("Failed to reopen " PIKE_POLL_DEVICE
" after fork (errno: %d).\n", errno);
}
if (fd != me->set) {
int e;
while (((e = dup2(fd, me->set)) < 0) && (errno == EINTR))
;
if (e < 0) {
/* We hope we can use the fd at the new location... */
me->set = fd;
} else {
while ((close(fd) < 0) && (errno == EINTR))
;
}
}
set_close_on_exec(me->set, 1);

/* Restore the poll-state for all the fds. */
{FOR_EACH_ACTIVE_FD_BOX (me->backend, box) {
pdb_UPDATE_BLACK_BOX (me, box->fd, box->events);
}}

}

#if defined(BACKEND_USES_CFRUNLOOP)
 static void noteEvents(CFFileDescriptorRef fdref,
CFOptionFlags UNUSED(callBackTypes),
void *info)
{
struct kevent kev;
struct timespec tv;
struct PollDeviceBackend_struct * this_backend;
int fd;
int numevts;

tv.tv_sec = 0;
tv.tv_nsec = 0;
this_backend = (struct PollDeviceBackend_struct *)info;
fd = CFFileDescriptorGetNativeDescriptor(fdref);
numevts = kevent(fd, NULL, 0, this_backend->poll_fds, POLL_SET_SIZE, &tv);
if (numevts >= 0)
this_backend->event_count = numevts;
else
this_backend->event_count = 0;
}
#endif /* BACKEND_USES_CFRUNLOOP */

static struct PollDeviceBackend_struct **pdb_backends = NULL;
static int num_pdb_backends = 0;
static int pdb_backends_size = 0;

/* Called from the init callback. */
static void register_pdb_backend(struct PollDeviceBackend_struct *me)
{
if (num_pdb_backends == pdb_backends_size) {
struct PollDeviceBackend_struct **new_backends =
realloc(pdb_backends,
(pdb_backends_size+1) *
sizeof(struct PollDeviceBackend_struct *)*2);
if (!new_backends) {
Pike_error("Out of memory.\n");
}
pdb_backends = new_backends;
pdb_backends_size = (pdb_backends_size+1)*2;
}
pdb_backends[num_pdb_backends++] = me;
}

/* Called from the exit callback. */
static void unregister_pdb_backend(struct PollDeviceBackend_struct *me)
{
int i = num_pdb_backends;
/* Search backwards since new backends are more likely to be destructed
     * than old backends.
     */
while (i--) {
if (pdb_backends[i] == me) {
pdb_backends[i] = pdb_backends[--num_pdb_backends];
pdb_backends[num_pdb_backends] = NULL;
return; /* A backend is only supposed to be registered once. */
}
}
}

/* Called in the child after fork(). */
static void reopen_all_pdb_backends(struct callback *UNUSED(cb),
void *UNUSED(a),
void *UNUSED(b))
{
int i;
for (i=0; i < num_pdb_backends; i++) {
pdb_REOPEN_POLL_DEVICE(pdb_backends[i]);
}
}

static void pdb_update_fd_set(struct Backend_struct *me,
struct PollDeviceBackend_struct *pdb, int fd,
int old_events, int new_events, 
#ifdef BACKEND_USES_POLL_DEVICE
 int PDUNUSED(flags)
#else
 int flags
#endif
 )
{
int changed_events = old_events ^ new_events;

IF_PD(fprintf(stderr,
"[%d]BACKEND[%d]: pdb_update_fd_set(.., %d, %d, %d, %d):\n",
THR_NO, me->id, fd, old_events, new_events, flags));


if (changed_events) {

#ifdef BACKEND_USES_POLL_DEVICE

pdb_UPDATE_BLACK_BOX(pdb, fd, new_events);

#elif defined(BACKEND_USES_KQUEUE)
 struct kevent ev[2];

if (changed_events & (PIKE_BIT_FD_READ|PIKE_BIT_FD_READ_OOB)) {
if (new_events & PIKE_BIT_FD_READ_OOB) {
/* We want OOB even if there's no in-band data. */
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: fd:%d READ, ADD, [OOBAND]\n",
THR_NO, me->id, fd));
EV_SET(ev, fd, EVFILT_READ, EV_ADD|EV_OOBAND, 0, 0, 0);
EV_SET(ev+1, fd, EVFILT_READ, EV_ENABLE|EV_OOBAND, 0, 0, 0);
kevent(pdb->set, ev, 2, NULL, 0, NULL);
} else if (new_events & PIKE_BIT_FD_READ) {
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: fd:%d READ, ADD\n",
THR_NO, me->id, fd));
EV_SET(ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
EV_SET(ev+1, fd, EVFILT_READ, EV_ENABLE, 0, 0, 0);
kevent(pdb->set, ev, 2, NULL, 0, NULL);
} else {
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: fd:%d READ, DISABLE\n",
THR_NO, me->id, fd));
pdb_MY_FD_CLR(&pdb->set, fd, MY_POLLIN);
}
}

if (changed_events & (PIKE_BIT_FD_WRITE|PIKE_BIT_FD_WRITE_OOB)) {
if (new_events & (PIKE_BIT_FD_WRITE|PIKE_BIT_FD_WRITE_OOB)) {
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: fd:%d WRITE, ADD\n",
THR_NO, me->id, fd));
pdb_MY_FD_SET(&pdb->set, fd, MY_POLLOUT);
} else {
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: fd:%d WRITE, DISABLE\n",
THR_NO, me->id, fd));
pdb_MY_FD_CLR(&pdb->set, fd, MY_POLLOUT);
}
}

/* TODO kqueue ADD fflags */
if (changed_events & PIKE_BIT_FD_FS_EVENT) {
if (new_events & PIKE_BIT_FD_FS_EVENT)
pdb_MY_FD_SET2(&pdb->set, fd, MY_POLLFSEVENT, flags);
else {
pdb_MY_FD_CLR(&pdb->set, fd, MY_POLLFSEVENT);
}
}

#else  /* !BACKEND_USES_POLL_DEVICE */
 if (changed_events & PIKE_BIT_FD_READ) {
if (new_events & PIKE_BIT_FD_READ) {
pdb_MY_FD_SET(&pdb->set, fd, MY_POLLIN);
/* Got to enable the exception set to get errors (at least
	   * according to POSIX). */
pdb_MY_FD_SET(&pdb->set, fd, MY_POLLEXCEPT);
}
else {
pdb_MY_FD_CLR(&pdb->set, fd, MY_POLLIN);
if (!(new_events & PIKE_BIT_FD_READ_OOB) &&
!(new_events & PIKE_BIT_FD_WRITE))
/* Exceptions might cause calls to read, read_oob and write. */
pdb_MY_FD_CLR(&pdb->set, fd, MY_POLLEXCEPT);
}
}

if (changed_events & PIKE_BIT_FD_READ_OOB) {
if (new_events & PIKE_BIT_FD_READ_OOB)
pdb_MY_FD_SET(&pdb->set, fd, MY_POLLRDBAND);
else {
if (!(new_events & PIKE_BIT_FD_READ)) {
if (!(new_events & PIKE_BIT_FD_WRITE))
/* Exceptions might cause calls to read, read_oob and write. */
pdb_MY_FD_CLR(&pdb->set, fd, MY_POLLEXCEPT);
} else {
pdb_MY_FD_CLR_RDBAND(&pdb->set, fd);
}
}
}

if (changed_events & PIKE_BIT_FD_WRITE) {
if (new_events & PIKE_BIT_FD_WRITE) {
pdb_MY_FD_SET(&pdb->set, fd, MY_POLLOUT);
/* Got to enable the exception set to get errors (at least
	   * according to POSIX). */
pdb_MY_FD_SET(&pdb->set, fd, MY_POLLEXCEPT);
}
else {
if (!(new_events & PIKE_BIT_FD_WRITE_OOB)) {
pdb_MY_FD_CLR(&pdb->set, fd, MY_POLLOUT);
if (!(new_events & PIKE_BIT_FD_READ) &&
!(new_events & PIKE_BIT_FD_READ_OOB))
/* Exceptions might cause calls to read, read_oob and write. */
pdb_MY_FD_CLR(&pdb->set, fd, MY_POLLEXCEPT);
}
}
}

if (changed_events & PIKE_BIT_FD_WRITE_OOB) {
if (new_events & PIKE_BIT_FD_WRITE_OOB)
pdb_MY_FD_SET(&pdb->set, fd, MY_POLLWRBAND);
else {
if (!(new_events & PIKE_BIT_FD_WRITE)) {
pdb_MY_FD_CLR(&pdb->set, fd, MY_POLLWREXCEPT);
} else {
pdb_MY_FD_CLR_WRBAND(&pdb->set, fd);
}
}
}



#endif	/* !BACKEND_USES_POLL_DEVICE */

if (new_events & ~old_events)
/* New events were added. */
backend_wake_up_backend(me);
}
}

/* Mapping of events to flags and callbacks.
   *
   * Event	select	poll		kqueue			callback
   *
   * data_in	read	POLLIN		EVFILT_READ		READ
   *			POLLRDNORM	EVFILT_READ[EOF]      
   *
   * data_out	write	POLLOUT		EVFILT_WRITE		WRITE
   *			POLLWRNORM
   *
   * oob_in	except	POLLPRI		EVFILT_READ[EV_OOBAND]	READ_OOB
   *			POLLRDBAND
   *
   * oob_out	write	POLLWRBAND	(EVFILT_WRITE)		WRITE_OOB
   *
   * close_in	read	POLLIN		EVFILT_READ[EOF]	READ
   *                    POLLHUP(Linux pipe)
   *
   * close_out	write	POLLHUP		EVFILT_WRITE[EOF]	WRITE
   *			POLLERR(Linux pipe)			>WRITE_OOB
   *
   * conn_ok	write	POLLOUT		EVFILT_WRITE		WRITE
   *
   * conn_fail	read	POLLIN		EVFILT_READ[EOF]	READ
   *		except						(READ_OOB)
   *
   * new_conn	read	POLLIN		EVFILT_READ		READ
   *
   * sock_err	except	POLLERR		EVFILT_READ[ERR]	ERROR
   *								>READ
   *
   * sock_err	except	POLLERR		EVFILT_WRITE[ERR]	ERROR
   *								>WRITE
   */

#ifdef POLL_DEBUG
 static void pdb_describe_event(struct Backend_struct *me, POLL_EVENT event)
{
#ifdef BACKEND_USES_KQUEUE
 fprintf(stderr, "[%d]BACKEND[%d]: fd:%d filter:%d flags:0x%08x",
THR_NO, me->id, PDB_GET_FD(event), PDB_GET_EVENTS(event),
event.flags);
if (PDB_CHECK_EVENT(event, MY_POLLIN)) {
fprintf(stderr, "  EVFILT_READ");
} else if (PDB_CHECK_EVENT(event, MY_POLLOUT)) {
fprintf(stderr, "  EVFILT_WRITE");
} else if (PDB_CHECK_EVENT(event, MY_POLLFSEVENT)) {
fprintf(stderr, "  POLLFSEVENT");
} else {
fprintf(stderr, "  UNKNOWN");
}
if (event.flags & EV_OOBAND) {
fprintf(stderr, "[OOBAND]");
}
if (event.flags & EV_ERROR) {
fprintf(stderr, "[ERROR]");
}
if (event.flags & EV_EOF) {
fprintf(stderr, "[EOF]");
}
fprintf(stderr, "(%d)\n", event.data);
#else /* !BACKEND_USES_KQUEUE */
 fprintf(stderr, "[%d]BACKEND[%d]: fd:%d events:0x%04x",
THR_NO, me->id, PDB_GET_FD(event), PDB_GET_EVENTS(event));
if (PDB_CHECK_EVENT(event, MY_POLLNVAL)) {
fprintf(stderr, "  POLLNVAL");
}
if (PDB_CHECK_EVENT(event, MY_POLLERR)) {
fprintf(stderr, "  POLLERR");
}
if (PDB_CHECK_EVENT(event, MY_POLLHUP)) {
fprintf(stderr, "  POLLHUP");
}
if (PDB_CHECK_EVENT(event, MY_POLLRDBAND)) {
fprintf(stderr, "  POLLRDBAND");
}
if (PDB_CHECK_EVENT(event, MY_POLLIN)) {
fprintf(stderr, "  POLLIN");
}
if (PDB_CHECK_EVENT(event, MY_POLLWRBAND)) {
fprintf(stderr, "  POLLWRBAND");
}
if (PDB_CHECK_EVENT(event, MY_POLLOUT)) {
fprintf(stderr, "  POLLOUT");
}
fprintf(stderr, "\n");
#endif /* BACKEND_USES_KQUEUE */
 }
#else /* !POLL_DEBUG */
#define pdb_describe_event(BACKEND, EVENT)
#endif /* POLL_DEBUG */

/* A negative tv_sec in timeout turns it off. If it ran until the
   * timeout without calling any callbacks or call outs (except those
   * on backend_callbacks) then tv_sec will be set to -1. Otherwise it
   * will be set to the time spent. */
static void pdb_low_backend_once(struct PollDeviceBackend_struct *pdb,
struct timeval *timeout)
{
ONERROR uwp;
int i, done_something = 0;
struct timeval start_time = *timeout;
struct Backend_struct *me = pdb->backend;

#ifdef DECLARE_POLL_EXTRAS
 /* Declare any extra variables needed by MY_POLL(). */
DECLARE_POLL_EXTRAS;
#endif /* DECLARE_POLL_EXTRAS */

if ((done_something =
low_backend_once_setup(pdb->backend, &start_time, &uwp))) {
goto low_backend_round_done;
}

if (TYPEOF(me->before_callback) != T_INT)
call_backend_monitor_cb (me, &me->before_callback);

{
#ifdef BACKEND_USES_CFRUNLOOP
 double cf_timeout;
#endif /* BACKEND_USES_CFRUNLOOP */

#ifdef TIMEOUT_IS_MILLISECONDS
 int poll_timeout;
#elif defined(TIMEOUT_IS_TIMEVAL)
 struct timeval poll_timeout;
#elif defined(TIMEOUT_IS_TIMESPEC)
 struct timespec poll_timeout;
#else
#error Unknown timeout method.
#endif /* TIMEOUT_IS_* */
 struct timeval *next_timeout = &pdb->backend->next_timeout;

me->may_need_wakeup = 1;

#ifdef TIMEOUT_IS_MILLISECONDS
 if (next_timeout->tv_sec >= 100000000)
/* Take this as waiting forever. */
poll_timeout = -1;
else if(next_timeout->tv_sec < 0)
poll_timeout = 0;
else if(next_timeout->tv_sec > (INT_MAX/1002)) /* about 24 days.*/
poll_timeout = INT_MAX/1002;
else
poll_timeout = (next_timeout->tv_sec*1000) +
(next_timeout->tv_usec + 999)/1000;
#elif defined(TIMEOUT_IS_TIMEVAL)
 poll_timeout = *next_timeout;
#elif defined(TIMEOUT_IS_TIMESPEC)
 poll_timeout.tv_sec = next_timeout->tv_sec;
poll_timeout.tv_nsec = next_timeout->tv_usec*1000;
#else
#error Unknown timeout method.
#endif /* TIMEOUT_IS_* */

IF_PD(fprintf (stderr, "[%d]BACKEND[%d]: Doing poll on fds:\n",
THR_NO, me->id));

check_threads_etc();
THREADS_ALLOW();

/* Note: The arguments to MY_POLL may be evaluated multiple times. */

#ifdef BACKEND_USES_CFRUNLOOP
 if(pdb->go_cf)
{
cf_timeout = next_timeout->tv_sec + (next_timeout->tv_usec / 1000000.0);

pdb->event_count = 0;
pdb->poll_fds = (poll_fds);

CFFileDescriptorEnableCallBacks(pdb->fdref,
kCFFileDescriptorReadCallBack);
CFRunLoopAddSource(CFRunLoopGetCurrent(), pdb->source,
kCFRunLoopDefaultMode);
CFRunLoopRunInMode(kCFRunLoopDefaultMode, cf_timeout, true);

i = pdb->event_count;
pdb->poll_fds = NULL;
}
else
#endif /* BACKEND_USES_CFRUNLOOP */
 i = PDB_POLL(pdb->set, poll_timeout);

IF_PD(fprintf(stderr, " => %d (timeout was: %d)\n", i, poll_timeout));

THREADS_DISALLOW();
check_threads_etc();
me->may_need_wakeup = 0;
INVALIDATE_CURRENT_TIME();
}

if (TYPEOF(me->after_callback) != T_INT)
call_backend_monitor_cb (me, &me->after_callback);

if (!i) {
/* Timeout */
} else if (i>0) {
int num_active = i;
struct fd_callback_box fd_list = {
me, NULL, &fd_list,
-1, 0, 0,
0, 0, NULL
};
struct fd_callback_box *box;
ONERROR free_fd_list;

SET_ONERROR(free_fd_list, do_free_fd_list, &fd_list);

done_something = 1;


#if 0
 /* First clear revents for all the fds.
       *
       * FIXME: This is done for paranoia reasons. If all code that
       *        messes with fds clears revents, this isn't needed.
       *
       * Note: This needs to be a separate loop, since kqueue sends
       *       read and write in two separate events.
       */
while(i--)
{
int fd = PDB_GET_FD(poll_fds[i]);

#ifdef BACKEND_USES_KQUEUE
 if(poll_fds[i].filter == MY_POLLSIGNAL)
{
continue;
}
#endif /* BACKEND_USES_KQUEUE */

box = SAFE_GET_ACTIVE_BOX (me, fd);
if (box) {
check_box (box, fd);
box->revents = 0;
box->rflags = 0;
}
}
#endif

/* Then flag the active events.
       */
i = num_active;
while(i--)
{
int fd = PDB_GET_FD(poll_fds[i]);

pdb_describe_event(me, poll_fds[i]);

if (!(box = SAFE_GET_ACTIVE_BOX (me, fd))) {
/* The box is no longer active. */
continue;
}

#ifdef MY_POLLNVAL
 if(PDB_CHECK_ERROR_EVENT(poll_fds[i], MY_POLLNVAL))
{
struct pollfd fds;
int ret;
/* NOTE: /dev/poll returns POLLNVAL for closed descriptors. */
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: POLLNVAL on %d\n",
THR_NO, me->id, fd));
#ifdef PIKE_DEBUG
#ifdef HAVE_POLL
 /* FIXME */

fds.fd=fd;
fds.events=POLLIN;
fds.revents=0;
ret=poll(&fds, 1,1 );
if(fds.revents & POLLNVAL)
Pike_fatal("Bad filedescriptor %d to poll().\n", fd);
#endif
 /* Don't do anything further with this fd. */
continue;
#endif /* PIKE_DEBUG */
 }
#endif /* MY_POLLNVAL */

check_box (box, fd);

{
#ifdef PIKE_DEBUG
 int handled = 0;
#endif /* PIKE_DEBUG */
 if (PDB_CHECK_ERROR_EVENT(poll_fds[i], MY_POLLERR)) {
/* Errors are signalled on the first available callback. */
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: POLLERR on %d\n",
THR_NO, me->id, fd));
box->revents |= PIKE_BIT_FD_ERROR;
/* Note that Linux pipe's signal close in the write-direction
	     * with POLLERR.
	     *
	     * FIXME: Signal on write-direction?
	     */
#ifdef BACKEND_USES_KQUEUE
 /* kqueue signals errors as read or write events but
	     * with an additional error flag, so we must take care
	     * to not set any read/write bits if it's a sole error
	     * event. */
if (!poll_fds[i].data) goto next_fd;
#endif
 }
if (PDB_CHECK_ERROR_EVENT(poll_fds[i], MY_POLLHUP)) {
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: POLLHUP on %d\n",
THR_NO, me->id, fd));
/* Linux signals close in the read-direction of pipes
	     * and fifos with POLLHUP. */
box->revents |= PIKE_BIT_FD_READ|PIKE_BIT_FD_READ_OOB;
/* For historical reasons we also signal on the write-drection. */
box->revents |= PIKE_BIT_FD_WRITE|PIKE_BIT_FD_WRITE_OOB;
DO_IF_DEBUG(handled = 1);
}
if (PDB_CHECK_EVENT(poll_fds[i], MY_POLLRDBAND)
#ifdef BACKEND_USES_KQUEUE
 && (!EV_OOBAND || PDB_CHECK_ERROR_EVENT(poll_fds[i], EV_OOBAND))
#endif
 ) {
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: POLLRDBAND on %d\n",
THR_NO, me->id, fd));
box->revents |= PIKE_BIT_FD_READ_OOB;
DO_IF_DEBUG(handled = 1);
}
if (PDB_CHECK_EVENT(poll_fds[i], MY_POLLIN)) {
IF_PD(fprintf(stderr,
"[%d]BACKEND[%d]: POLLRDNORM|POLLIN on %d\n",
THR_NO, me->id, fd));
box->revents |= PIKE_BIT_FD_READ;
DO_IF_DEBUG(handled = 1);
}
if (PDB_CHECK_EVENT(poll_fds[i], MY_POLLWRBAND)) {
IF_PD(fprintf(stderr,
"[%d]BACKEND[%d]: POLLWRBAND on %d\n",
THR_NO, me->id, fd));
box->revents |= PIKE_BIT_FD_WRITE_OOB;
DO_IF_DEBUG(handled = 1);
}
if (PDB_CHECK_EVENT(poll_fds[i], MY_POLLOUT)) {
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: POLLOUT on %d\n",
THR_NO, me->id, fd));
box->revents |= PIKE_BIT_FD_WRITE;
DO_IF_DEBUG(handled = 1);
}
if (PDB_CHECK_EVENT(poll_fds[i], MY_POLLFSEVENT)) {
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: POLLFSEVENT on %d\n",
THR_NO, me->id, fd));
box->revents |= PIKE_BIT_FD_FS_EVENT;
DO_IF_DEBUG(handled = 1);
}
#ifdef PIKE_DEBUG
 if (!handled && PDB_GET_EVENTS(poll_fds[i])) {
fprintf(stderr, "[%d]BACKEND[%d]: fd %ld has revents 0x%08lx, "
"but hasn't been handled.\n", THR_NO, me->id,
(long)PDB_GET_FD(poll_fds[i]),
(long)PDB_GET_EVENTS(poll_fds[i]));
pdb_describe_event(me, poll_fds[i]);
}
#endif /* PIKE_DEBUG */
 }
if (box->revents) {
if (!(box->revents & (box->events | PIKE_BIT_FD_ERROR))) {
/* Robustness paranoia; we've only received events that we
	     * aren't interested in. Unregister the unwanted events
	     * in case we are out of sync with the poll device.
	     * Otherwise we risk entering a busy loop.
	     */
IF_PD(fprintf(stderr,
"[%d]BACKEND[%d]: Backend is out of sync for fd %d\n"
"[%d]BACKEND[%d]: Wanted: 0x%04x Received: 0x%04x\n",
THR_NO, me->id, fd,
THR_NO, me->id, box->events, box->revents));
pdb_update_fd_set(me, pdb, fd, box->revents|box->events,
box->events, box->flags);
}
next_fd:
/* Hook in the box on the fd_list. */
if (!box->next) {
IF_PD(fprintf(stderr,
"[%d]BACKEND[%d]: hooking in box for fd %d\n",
THR_NO, me->id, fd));
box->next = fd_list.next;
fd_list.next = box;
if (box->ref_obj) add_ref(box->ref_obj);
} else {
IF_PD(fprintf(stderr,
"[%d]BACKEND[%d]: fd %d already in list.\n",
THR_NO, me->id, fd));
}
}
}

/* Common code for all variants.
       *
       * Call callbacks for the active events.
       */
if (backend_call_active_callbacks(&fd_list, me)) {
CALL_AND_UNSET_ONERROR(free_fd_list);
goto backend_round_done;
}

CALL_AND_UNSET_ONERROR(free_fd_list);

/* Must be up-to-date for backend_do_call_outs. */
INVALIDATE_CURRENT_TIME();
}else{
switch(errno)
{
#ifdef __NT__
 default:
Pike_fatal("Error in backend %d\n",errno);
break;
#endif
 
case EINVAL:
Pike_fatal("Invalid timeout to select().\n");
break;

#ifdef WSAEINTR
 case WSAEINTR:
#endif
 case EINTR: /* ignore */
break;

#ifdef WSAEBADF
 case WSAEBADF:
#endif
#ifdef ENOTSOCK
 case ENOTSOCK:
#endif
#ifdef WSAENOTSOCK
 case WSAENOTSOCK:
#endif
 case EBADF:
/* TODO: Fix poll version! */
break;

}
}

{
int call_outs_called =
backend_do_call_outs(me); /* Will update current_time after calls. */
if (call_outs_called)
done_something = 1;
if (call_outs_called < 0)
goto backend_round_done;
}

call_callback(&me->backend_callbacks, NULL);

backend_round_done:

#ifdef PIKE_THREADS
 me->done_counter += done_something;

co_broadcast(&me->backend_signal);
#endif

CALL_AND_UNSET_ONERROR (uwp);

low_backend_round_done:
if (done_something <= 0)
timeout->tv_sec = -1;
else {
struct timeval now;
INACCURATE_GETTIMEOFDAY(&now);
timeout->tv_sec = now.tv_sec;
timeout->tv_usec = now.tv_usec;
my_subtract_timeval (timeout, &start_time);
}
}

#ifdef BACKEND_USES_CFRUNLOOP
 void cfTimerCallback(CFRunLoopTimerRef UNUSED(timer), void * info)
{
struct PollDeviceBackend_struct *me;
struct timeval timeout;
me = (struct PollDeviceBackend_struct *)info; 

timeout.tv_sec = 0;
timeout.tv_usec = 0;

pdb_low_backend_once(me, &timeout); 
}

/* our external CFRunLoop has received events or timed out. We should
     do a once-through the runloop to find out if there's anything to do. */
void cfObserverCallback(CFRunLoopObserverRef UNUSED(observer),
CFRunLoopActivity activity, void* info)
{
struct timeval timeout;
struct thread_state *cur_ts__;
struct PollDeviceBackend_struct *me;
me = (struct PollDeviceBackend_struct *)info; 

switch(activity)
{
case kCFRunLoopEntry:
/* release the interpreter lock. */
me->gil_released = 1;
{
cur_ts__ = Pike_interpreter.thread_state; 
me->thread_state = cur_ts__; /* for use later. */
pike_threads_allow (cur_ts__ COMMA_DLOC);
}
break;

case kCFRunLoopBeforeTimers:
case kCFRunLoopBeforeSources:
/* gain the interpreter lock, if released. */
if(me->gil_released)
{
cur_ts__ = me->thread_state;
me->gil_released = 0;
pike_threads_disallow (cur_ts__ COMMA_DLOC);
me->thread_state = 0;
}
break;

case kCFRunLoopExit:
if(me->gil_released)
{
cur_ts__ = me->thread_state;
me->gil_released = 0;
pike_threads_disallow (cur_ts__ COMMA_DLOC);
me->thread_state = 0;
}
timeout.tv_sec = 0;
timeout.tv_usec = 0;
pdb_low_backend_once(me, &timeout);
break;
}

}
#endif /* BACKEND_USES_CFRUNLOOP */

/*! @decl float|int(0..0) `()(void|float|int(0..0) sleep_time)
   *!   Perform one pass through the backend.
   *!
   *!   Calls any outstanding call-outs and non-blocking I/O
   *!   callbacks that are registred in this backend object.
   *!
   *! @param sleep_time
   *!   Wait at most @[sleep_time] seconds. The default when
   *!   unspecified or the integer @expr{0@} is no time limit.
   *!
   *! @returns
   *!   If the backend did call any callbacks or call outs then the
   *!   time spent in the backend is returned as a float. Otherwise
   *!   the integer @expr{0@} is returned.
   *!
   *! @seealso
   *!   @[Pike.DefaultBackend], @[main()]
   */
#define f_PollDeviceBackend_cq__backtick_28_29_defined

#ifdef f_PollDeviceBackend_cq__backtick_28_29_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_PollDeviceBackend_cq__backtick_28_29_fun_num = 0;

#endif /* f_PollDeviceBackend_cq__backtick_28_29_fun_num_used */
DEFAULT_CMOD_STORAGE void f_PollDeviceBackend_cq__backtick_28_29(INT32 args) {
#line 4297 "/Users/hww3/devel/pike/src/backend.cmod"
struct svalue * sleep_time;
#line 4297 "/Users/hww3/devel/pike/src/backend.cmod"
if(args > 1) wrong_number_of_args_error("`()",args,1);
#line 4297 "/Users/hww3/devel/pike/src/backend.cmod"
if ((args > 0) &&
    ((TYPEOF(Pike_sp[0-args]) != PIKE_T_INT) ||
     (SUBTYPEOF(Pike_sp[0-args]) != NUMBER_UNDEFINED))) {
#line 4297 "/Users/hww3/devel/pike/src/backend.cmod"
sleep_time=Pike_sp+0-args; dmalloc_touch_svalue(Pike_sp+0-args);
#line 4297 "/Users/hww3/devel/pike/src/backend.cmod"
} else sleep_time = NULL;
{
struct timeval timeout; /* Got bogus gcc warning on timeout.tv_usec. */

timeout.tv_sec = 0;
timeout.tv_usec = 0;

if (sleep_time && TYPEOF(*sleep_time) == PIKE_T_FLOAT) {
timeout.tv_sec = (long) floor (sleep_time->u.float_number);
timeout.tv_usec =
(long) ((sleep_time->u.float_number - timeout.tv_sec) * 1e6);
}
else if (sleep_time && TYPEOF(*sleep_time) == T_INT &&
sleep_time->u.integer) {
SIMPLE_BAD_ARG_ERROR("`()", 1, "float|int(0..0)");
}
else
timeout.tv_sec = -1;

pdb_low_backend_once(THIS, &timeout);

pop_n_elems (args);
if (timeout.tv_sec < 0)
push_int (0);
else
push_float (DO_NOT_WARN ((FLOAT_TYPE)
(DO_NOT_WARN ((double) timeout.tv_sec) +
DO_NOT_WARN ((double) timeout.tv_usec) / 1e6)));
}

}
#line 4327 "/Users/hww3/devel/pike/src/backend.cmod"
#ifdef BACKEND_USES_CFRUNLOOP
/*! @decl int enable_core_foundation(int(0..1) enable)
 *!   On systems with CoreFoundation (OSX, iOS, etc), use CoreFoundation
 *!   to poll for events. This enables system level technologies that rely
 *!   on CoreFoundation Runloops to function properly.
 *!
 *!  @param enable
 *!    enable or disable this functionality
 *!
 *!  @returns
 *!    the previous value of this setting.
 *!
 */
#define f_PollDeviceBackend_enable_core_foundation_defined

#ifdef f_PollDeviceBackend_enable_core_foundation_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_PollDeviceBackend_enable_core_foundation_fun_num = 0;

#endif /* f_PollDeviceBackend_enable_core_foundation_fun_num_used */
DEFAULT_CMOD_STORAGE void f_PollDeviceBackend_enable_core_foundation(INT32 args) {
#line 4340 "/Users/hww3/devel/pike/src/backend.cmod"
INT_TYPE enable;
#line 4340 "/Users/hww3/devel/pike/src/backend.cmod"
if(args != 1) wrong_number_of_args_error("enable_core_foundation",args,1);
#line 4340 "/Users/hww3/devel/pike/src/backend.cmod"
if(TYPEOF(Pike_sp[0-1]) != PIKE_T_INT) SIMPLE_ARG_TYPE_ERROR("enable_core_foundation",1,"int");
#line 4340 "/Users/hww3/devel/pike/src/backend.cmod"
enable=Pike_sp[0-1].u.integer;
{
int x = THIS->go_cf;

if(enable && !THIS->go_cf)
{
THIS->go_cf = 1;
init_cf(THIS, THIS->set);
}
else if(!enable && THIS->go_cf)
{
THIS->go_cf = 0;
if(THIS->external_run)
exit_external_cfrl(THIS);
exit_cf(THIS);
}
pop_stack();

push_int(x);
}

}
/*! @decl int query_core_foundation_enabled()
 *!
 *! On systems with CoreFoundation (OSX, iOS, etc), indicate whether
 *! CoreFoundation is being used by this backend to poll for events.
 *!
 *! @returns
 *! the current state of CoreFoundation polling: 1=enabled, 0=disabled
 *!
 */
#define f_PollDeviceBackend_query_core_foundation_enabled_defined

#ifdef f_PollDeviceBackend_query_core_foundation_enabled_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_PollDeviceBackend_query_core_foundation_enabled_fun_num = 0;

#endif /* f_PollDeviceBackend_query_core_foundation_enabled_fun_num_used */
DEFAULT_CMOD_STORAGE void f_PollDeviceBackend_query_core_foundation_enabled(INT32 args) {
#line 4370 "/Users/hww3/devel/pike/src/backend.cmod"
if(args != 0) wrong_number_of_args_error("query_core_foundation_enabled",args,0);
{
int x = THIS->go_cf;

push_int(x);
return;
}

}
/*! @decl int enable_external_runloop(int(0..1) enable)
 *!   On systems with CoreFoundation (OSX, iOS, etc), delegate 
 *!   running of the Pike Backend to the main runloop of the 
 *!   process (such as a Cocoa application's NSRunLoop). 
 *!
 *!   Enabling the external runloop allows Pike callouts and 
 *!   callback-based I/O to function normally while greatly reducing 
 *!   cpu utilization compared to running the external runloop
 *!   manually.
 *!
 *!  @param enable
 *!    enable or disable this functionality
 *!
 *!  @returns
 *!    the previous value of this setting.
 *!
 */
#define f_PollDeviceBackend_enable_external_runloop_defined

#ifdef f_PollDeviceBackend_enable_external_runloop_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_PollDeviceBackend_enable_external_runloop_fun_num = 0;

#endif /* f_PollDeviceBackend_enable_external_runloop_fun_num_used */
DEFAULT_CMOD_STORAGE void f_PollDeviceBackend_enable_external_runloop(INT32 args) {
#line 4395 "/Users/hww3/devel/pike/src/backend.cmod"
INT_TYPE enable;
#line 4395 "/Users/hww3/devel/pike/src/backend.cmod"
if(args != 1) wrong_number_of_args_error("enable_external_runloop",args,1);
#line 4395 "/Users/hww3/devel/pike/src/backend.cmod"
if(TYPEOF(Pike_sp[0-1]) != PIKE_T_INT) SIMPLE_ARG_TYPE_ERROR("enable_external_runloop",1,"int");
#line 4395 "/Users/hww3/devel/pike/src/backend.cmod"
enable=Pike_sp[0-1].u.integer;
{
int x = THIS->external_run;

if(enable && !THIS->external_run)
{
THIS->external_run = 1;

if(!THIS->go_cf)
init_cf(THIS, THIS->set);

init_external_cfrl(THIS, THIS->set);
}
else if(!enable && THIS->external_run)
{
THIS->external_run = 0;
exit_external_cfrl(THIS);
}
pop_stack();

push_int(x);
}

}
#line 4418 "/Users/hww3/devel/pike/src/backend.cmod"
#endif /* BACKEND_USES_CFRUNLOOP */



#undef extra_PollDeviceBackend_defined
#define extra_PollDeviceBackend_defined

#undef internal_init_PollDeviceBackend_defined
#define internal_init_PollDeviceBackend_defined

#undef PollDeviceBackend_event_handler_defined
#define PollDeviceBackend_event_handler_defined
static void init_PollDeviceBackend_struct(void)
#line 4441 "/Users/hww3/devel/pike/src/backend.cmod"
{
struct Backend_struct *me =
THIS->backend = (struct Backend_struct *)(((char *)THIS) + pdb_offset);

IF_PD (fprintf (stderr, "[%d]BACKEND[%d]: Registering device backend...\n",
THR_NO, me->id));

me->update_fd_set_handler = (update_fd_set_handler_fn *) pdb_update_fd_set;
me->handler_data = THIS;

IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: Registering backend...\n",
THR_NO, me->id));
register_pdb_backend(THIS);

IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: Opening poll device...\n",
THR_NO, me->id));
if ((THIS->set = OPEN_POLL_DEVICE(THIS)) < 0) {
Pike_error("Failed to open poll device (errno:%d)\n", errno);
}
set_close_on_exec(THIS->set, 1);
}


#undef internal_exit_PollDeviceBackend_defined
#define internal_exit_PollDeviceBackend_defined

#undef PollDeviceBackend_event_handler_defined
#define PollDeviceBackend_event_handler_defined
static void exit_PollDeviceBackend_struct(void)
#line 4465 "/Users/hww3/devel/pike/src/backend.cmod"
{
struct Backend_struct *me = THIS->backend;

IF_PD (fprintf (stderr, "[%d]BACKEND[%d]: Closing poll device...\n",
THR_NO, me->id));

#ifdef BACKEND_USES_CFRUNLOOP 
 if(THIS->external_run)
exit_external_cfrl(THIS);
exit_cf(THIS);
#endif /* BACKEND_USES_CFRUNLOOP */

if (THIS->set >= 0)
fd_close(THIS->set);

unregister_pdb_backend(THIS);
}

#ifdef PollDeviceBackend_event_handler_defined
static void PollDeviceBackend_event_handler(int ev) {
  switch(ev) {

#ifdef internal_init_PollDeviceBackend_defined
  case PROG_EVENT_INIT: init_PollDeviceBackend_struct(); break;

#endif /* internal_init_PollDeviceBackend_defined */

#ifdef internal_exit_PollDeviceBackend_defined
  case PROG_EVENT_EXIT: exit_PollDeviceBackend_struct(); break;

#endif /* internal_exit_PollDeviceBackend_defined */
  default: break; 
  }
}

#endif /* PollDeviceBackend_event_handler_defined */
/*! @endclass
 */

#line 4487 "/Users/hww3/devel/pike/src/backend.cmod"
#endif /* BACKEND_USES_POLL_DEVICE || BACKEND_USES_KQUEUE */

#ifdef BACKEND_USES_CFRUNLOOP
static void check_set_timer(struct timeval tmp)
{
{
/* register a timer if the backend is using external cfrl. */
struct external_variable_context loc;
struct PollDeviceBackend_struct * pdb = NULL;
char * _st = NULL;
loc.o = Pike_fp->current_object;
loc.parent_identifier = 0;
loc.inherit = Pike_fp->context;

find_external_context(&loc, 1);

if (!loc.o->prog)
{
Pike_error ("Cannot access storage of destructed parent object.\n");
}

_st = get_storage(loc.o, PollDeviceBackend_program);

pdb = (struct PollDeviceBackend_struct *)_st;

if(pdb && pdb->external_run)
{
CFRunLoopTimerContext context = {0, pdb, NULL, NULL, NULL};
CFRunLoopTimerRef timer; 
CFTimeInterval when = 0.0;

when = (CFTimeInterval)tmp.tv_sec +
(1.0E-6 * (CFTimeInterval) tmp.tv_usec);
timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + when, 0,
0, 0, &cfTimerCallback, &context);

if(timer)
{
/* set the timer. */
CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
}
else
{
Pike_error("Unable to create run loop timer!\n");
}
}
}
}
#endif /* BACKEND_USES_CFRUNLOOP */

#ifdef HAVE_POLL

/*! @class PollBackend
 *! @inherit __Backend
 *!
 *! @[Backend] implemented with @tt{poll(2)@} (SVr4, POSIX).
 *!
 *! @seealso
 *!   @[Backend]
 */

#undef class_PollBackend_defined
#define class_PollBackend_defined
DEFAULT_CMOD_STORAGE struct program *PollBackend_program=NULL;

#ifdef PollBackend_program_fun_num_used
DEFAULT_CMOD_STORAGE int PollBackend_program_fun_num=-1;
#endif /* PollBackend_program_fun_num_used */

#undef inherit_Backend_PollBackend_defined
#define inherit_Backend_PollBackend_defined
#line 4549 "/Users/hww3/devel/pike/src/backend.cmod"
static int PollBackend_Backend_inh_num = -1;
#line 4549 "/Users/hww3/devel/pike/src/backend.cmod"
static int PollBackend_Backend_inh_offset = -1;
#line 4551 "/Users/hww3/devel/pike/src/backend.cmod"
/* Helpers to find the above inherit. */
static ptrdiff_t pb_offset = 0;

#undef var_backend_PollBackend_defined
#define var_backend_PollBackend_defined
#line 4555 "/Users/hww3/devel/pike/src/backend.cmod"
/* 
   * POLL/SELECT fd sets
   */

#undef var_set_PollBackend_defined
#define var_set_PollBackend_defined

#undef var_active_set_PollBackend_defined
#define var_active_set_PollBackend_defined

#undef THIS
#define THIS ((struct PollBackend_struct *)(Pike_interpreter.frame_pointer->current_storage))

#undef THIS_POLLBACKEND
#define THIS_POLLBACKEND ((struct PollBackend_struct *)(Pike_interpreter.frame_pointer->current_storage))

#undef OBJ2_POLLBACKEND
#define OBJ2_POLLBACKEND(o) ((struct PollBackend_struct *)(o->storage+PollBackend_storage_offset))

#undef GET_POLLBACKEND_STORAGE
#define GET_POLLBACKEND_STORAGE(o) ((struct PollBackend_struct *)(o->storage+PollBackend_storage_offset)
static ptrdiff_t PollBackend_storage_offset;
struct PollBackend_struct {

#ifdef var_backend_PollBackend_defined
#line 4553 "/Users/hww3/devel/pike/src/backend.cmod"
struct Backend_struct *backend;
#endif /* var_backend_PollBackend_defined */

#ifdef var_set_PollBackend_defined
#line 4558 "/Users/hww3/devel/pike/src/backend.cmod"
struct pb_selectors set;
#endif /* var_set_PollBackend_defined */

#ifdef var_active_set_PollBackend_defined
#line 4559 "/Users/hww3/devel/pike/src/backend.cmod"
struct pb_selectors active_set;
#endif /* var_active_set_PollBackend_defined */
};
#ifdef PIKE_DEBUG
/* Ensure the struct is used in a variable declaration, or else gdb might not see it. */
static struct PollBackend_struct *PollBackend_gdb_dummy_ptr;
#endif
#line 4563 "/Users/hww3/devel/pike/src/backend.cmod"
/*
   * FD set handling
   */

static void pb_update_fd_set (struct Backend_struct *me,
struct PollBackend_struct *pb, int fd,
int old_events, int new_events,
int UNUSED(flags))
{
int changed_events = old_events ^ new_events;

IF_PD(fprintf(stderr,
"[%d]BACKEND[%d]: pb_update_fd_set(.., %d, %d, %d):\n",
THR_NO, me->id, fd, old_events, new_events));


if (changed_events) {

if (changed_events & PIKE_BIT_FD_READ) {
if (new_events & PIKE_BIT_FD_READ) {
pb_MY_FD_SET(&pb->set, fd, MY_POLLIN);
}
else {
pb_MY_FD_CLR(&pb->set, fd, MY_POLLIN);
if (new_events & PIKE_BIT_FD_READ_OOB)
{
pb_MY_FD_SET(&pb->set, fd, MY_POLLRDBAND);
}
}
}

if (changed_events & PIKE_BIT_FD_READ_OOB) {
if (new_events & PIKE_BIT_FD_READ_OOB)
pb_MY_FD_SET(&pb->set, fd, MY_POLLRDBAND);
else {
if (!(new_events & PIKE_BIT_FD_READ)) {
pb_MY_FD_CLR(&pb->set, fd, MY_POLLRDBAND);
} else {
pb_MY_FD_CLR_RDBAND(&pb->set, fd);
}
}
}

if (changed_events & PIKE_BIT_FD_WRITE) {
if (new_events & PIKE_BIT_FD_WRITE) {
pb_MY_FD_SET(&pb->set, fd, MY_POLLOUT);
}
else {
if (!(new_events & PIKE_BIT_FD_WRITE_OOB)) {
pb_MY_FD_CLR(&pb->set, fd, MY_POLLOUT);
}
}
}

if (changed_events & PIKE_BIT_FD_WRITE_OOB) {
if (new_events & PIKE_BIT_FD_WRITE_OOB)
pb_MY_FD_SET(&pb->set, fd, MY_POLLWRBAND);
else {
if (!(new_events & PIKE_BIT_FD_WRITE)) {
pb_MY_FD_CLR(&pb->set, fd, MY_POLLWREXCEPT);
} else {
pb_MY_FD_CLR_WRBAND(&pb->set, fd);
}
}
}

if (new_events & ~old_events)
/* New events were added. */
backend_wake_up_backend (me);
}
}

#ifdef PIKE_DEBUG

static void pb_backend_do_debug(struct Backend_struct *me,
struct PollBackend_struct *pb)
{
int e;

/* FIXME: OOB? */
for(e=0;e<pb->set.num_in_poll;e++)
{
PIKE_STAT_T tmp;
int ret;
int fd = pb->set.poll_fds[e].fd;

if (fd >= fd_map_size || fd_map[fd] != me)
Pike_fatal("Unmapped fd %d at %d in poll set.\n", fd, e);

do {
ret=fd_fstat(fd, &tmp);
/* FIXME: Perhaps do check_threads_etc() here? */
}while(ret < 0 && errno == EINTR);

if(ret<0)
{
switch(errno)
{
case EBADF:
Pike_fatal("Backend filedescriptor %d is bad.\n", fd);
break;
case ENOENT:
Pike_fatal("Backend filedescriptor %d is not.\n", fd);
break;
}
}
}
}

#endif	/* PIKE_DEBUG */

/* Mapping of events to flags and callbacks.
   *
   * Event	select	poll		kqueue			callback
   *
   * data_in	read	POLLIN		EVFILT_READ		READ
   *			POLLRDNORM	EVFILT_READ[EOF]      
   *
   * data_out	write	POLLOUT		EVFILT_WRITE		WRITE
   *			POLLWRNORM
   *
   * oob_in	except	POLLPRI		(EVFILT_READ)		READ_OOB
   *			POLLRDBAND
   *
   * oob_out	write	POLLWRBAND	(EVFILT_WRITE)		WRITE_OOB
   *
   * close_in	read	POLLIN		EVFILT_READ[EOF]	READ
   *
   * close_out	write	POLLHUP		EVFILT_WRITE[EOF]	WRITE
   *								>WRITE_OOB
   *
   * conn_ok	write	POLLOUT		EVFILT_WRITE		WRITE
   *
   * conn_fail	read	POLLIN		EVFILT_READ[EOF]	READ
   *		except						(READ_OOB)
   *
   * new_conn	read	POLLIN		EVFILT_READ		READ
   *
   * sock_err	except	POLLERR		EVFILT_READ[ERR]	ERROR
   *								>READ
   *
   * sock_err	except	POLLERR		EVFILT_WRITE[ERR]	ERROR
   *								>WRITE
   * fs_event	NONE	NONE		EVFILT_VNODE	FSEVENT
   */


/* A negative tv_sec in timeout turns it off. If it ran until the
   * timeout without calling any callbacks or call outs (except those
   * on backend_callbacks) then tv_sec will be set to -1. Otherwise it
   * will be set to the time spent. */
static void pb_low_backend_once(struct PollBackend_struct *pb,
struct timeval *timeout)
{
ONERROR uwp;
int i, done_something = 0;
struct timeval start_time = *timeout;
struct Backend_struct *me = pb->backend;
#ifdef DECLARE_POLL_EXTRAS
 /* Declare any extra variables needed by MY_POLL(). */
DECLARE_POLL_EXTRAS;
#endif /* DECLARE_POLL_EXTRAS */

if ((done_something =
low_backend_once_setup(pb->backend, &start_time, &uwp))) {
goto low_backend_round_done;
}

if (TYPEOF(me->before_callback) != T_INT)
call_backend_monitor_cb (me, &me->before_callback);

{
int poll_timeout;
struct timeval *next_timeout = &pb->backend->next_timeout;

me->may_need_wakeup = 1;

if (next_timeout->tv_sec >= 100000000)
/* Take this as waiting forever. */
poll_timeout = -1;
else if(next_timeout->tv_sec < 0)
poll_timeout = 0;
else if(next_timeout->tv_sec > (INT_MAX/1002))
poll_timeout = INT_MAX;
else
poll_timeout = (next_timeout->tv_sec*1000) +
(next_timeout->tv_usec + 999)/1000;

pb_copy_selectors(& pb->active_set, &pb->set);

IF_PD(fprintf (stderr, "[%d]BACKEND[%d]: Doing poll on fds:\n",
THR_NO, me->id));
#ifdef POLL_DEBUG
 {
int i;
for (i = 0; i < pb->active_set.num_in_poll; i++) {
fprintf (stderr,
"[%d]BACKEND[%d]:   fd %4d: %-4s %-5s %-8s %-9s: 0x%04x\n",
THR_NO, me->id,
pb->active_set.poll_fds[i].fd,
pb->active_set.poll_fds[i].events & (POLLRDNORM|POLLIN) ?
"read" : "",
pb->active_set.poll_fds[i].events & POLLOUT ?
"write" : "",
pb->active_set.poll_fds[i].events & POLLRDBAND ?
"read_oob" : "",
pb->active_set.poll_fds[i].events & POLLWRBAND ?
"write_oob" : "",
pb->active_set.poll_fds[i].events);
}
}
fprintf(stderr, "[%d]BACKEND[%d]: poll(%p, %d, %d)...", THR_NO, me->id,
pb->active_set.poll_fds,
pb->active_set.num_in_poll,
poll_timeout);
#endif /* POLL_DEBUG */

check_threads_etc();
THREADS_ALLOW();

/* Note: The arguments to MY_POLL may be evaluated multiple times. */
i = PB_POLL(pb->active_set, poll_timeout);

IF_PD(fprintf(stderr, " => %d\n", i));

THREADS_DISALLOW();
check_threads_etc();
me->may_need_wakeup = 0;
INVALIDATE_CURRENT_TIME();
}

if (TYPEOF(me->after_callback) != T_INT)
call_backend_monitor_cb (me, &me->after_callback);

if (!i) {
/* Timeout */
} else if (i>0) {
int num_active = i;
struct fd_callback_box fd_list = {
NULL, NULL, NULL,
-1, 0, 0,
0, 0, NULL,
};
struct fd_callback_box *box;
ONERROR free_fd_list;

fd_list.backend = me;
fd_list.next = &fd_list;

SET_ONERROR(free_fd_list, do_free_fd_list, &fd_list);

done_something = 1;


/* First clear revents for all the fds.
       *
       * FIXME: This is done for paranoia reasons. If all code that
       *        messes with fds clears revents, this isn't needed.
       *
       * Note: this needs to be a separate loop, since kqueue sends
       *       read and write in two separate events.
       */
for(i=0; i<pb->active_set.num_in_poll; i++)
{
int fd = PB_GET_FD(pb->active_set.poll_fds[i]);
box = SAFE_GET_ACTIVE_BOX (me, fd);
if (box) {
check_box (box, fd);
box->revents = 0;
box->flags = 0;
}
}

/* Then flag the active events.
       */
for(i=0; i<pb->active_set.num_in_poll; i++)
{
int fd = PB_GET_FD(pb->active_set.poll_fds[i]);

if (!(box = SAFE_GET_ACTIVE_BOX (me, fd))) {
/* The box is no longer active. */
continue;
}

#ifdef MY_POLLNVAL
 if(PB_CHECK_ERROR_EVENT(pb->active_set.poll_fds[i], MY_POLLNVAL))
{
struct pollfd fds;
int ret;
/* NOTE: /dev/poll returns POLLNVAL for closed descriptors. */
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: POLLNVAL on %d\n",
THR_NO, me->id, fd));
#ifdef PIKE_DEBUG
 /* FIXME */

fds.fd=fd;
fds.events=POLLIN;
fds.revents=0;
ret=poll(&fds, 1,1 );
if(fds.revents & POLLNVAL)
Pike_fatal("Bad filedescriptor %d to poll().\n", fd);
/* Don't do anything further with this fd. */
continue;
#endif /* PIKE_DEBUG */
 }
#endif /* MY_POLLNVAL */

check_box (box, fd);

#if 0
 if(PDB_CHECK_EVENT(poll_fds[i], MY_POLLSIGNAL))
{
fprintf(stderr, "SIGNAL EVENT RECEIVED!\n");
}
#endif

{
#ifdef PIKE_DEBUG
 int handled = 0;
#endif /* PIKE_DEBUG */
 if (PB_CHECK_ERROR_EVENT(pb->active_set.poll_fds[i], MY_POLLERR)) {
/* Errors are signalled on the first available callback. */
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: POLLERR on %d\n",
THR_NO, me->id, fd));
box->revents |= PIKE_BIT_FD_ERROR;
}

if (PB_CHECK_EVENT(pb->active_set.poll_fds[i], MY_POLLRDBAND) ||
PB_CHECK_ERROR_EVENT(pb->active_set.poll_fds[i], MY_POLLHUP)) {
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: POLLRDBAND|POLLHUP on %d\n",
THR_NO, me->id, fd));
box->revents |= PIKE_BIT_FD_READ_OOB;
DO_IF_DEBUG(handled = 1);
}
if (PB_CHECK_EVENT(pb->active_set.poll_fds[i], MY_POLLIN) ||
PB_CHECK_ERROR_EVENT(pb->active_set.poll_fds[i], MY_POLLHUP)) {
IF_PD(fprintf(stderr,
"[%d]BACKEND[%d]: POLLRDNORM|POLLIN|POLLHUP on %d\n",
THR_NO, me->id, fd));
box->revents |= PIKE_BIT_FD_READ;
DO_IF_DEBUG(handled = 1);
}
if (PB_CHECK_EVENT(pb->active_set.poll_fds[i], MY_POLLWRBAND) ||
PB_CHECK_ERROR_EVENT(pb->active_set.poll_fds[i], MY_POLLHUP)) {
IF_PD(fprintf(stderr,
"[%d]BACKEND[%d]: POLLWRBAND|POLLHUP on %d\n",
THR_NO, me->id, fd));
box->revents |= PIKE_BIT_FD_WRITE_OOB;
DO_IF_DEBUG(handled = 1);
}
if (PB_CHECK_EVENT(pb->active_set.poll_fds[i], MY_POLLOUT) ||
PB_CHECK_ERROR_EVENT(pb->active_set.poll_fds[i], MY_POLLHUP)) {
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: POLLOUT|POLLHUP on %d\n",
THR_NO, me->id, fd));
box->revents |= PIKE_BIT_FD_WRITE;
DO_IF_DEBUG(handled = 1);
}
if (PDB_CHECK_EVENT(pb->active_set.poll_fds[i], MY_POLLFSEVENT)) {
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: POLLFSEVENT on %d\n",
THR_NO, me->id, fd));
box->rflags = PDB_GET_FLAGS(poll_fds[i]);
box->revents |= PIKE_BIT_FD_FS_EVENT;
DO_IF_DEBUG(handled = 1);
}
#ifdef PIKE_DEBUG
 if (!handled && PB_GET_EVENTS(pb->active_set.poll_fds[i])) {
fprintf(stderr, "[%d]BACKEND[%d]: fd %ld has revents 0x%08lx, "
"but hasn't been handled.\n", THR_NO, me->id,
(long)PB_GET_FD(pb->active_set.poll_fds[i]),
(long)PB_GET_EVENTS(pb->active_set.poll_fds[i]));
/* pdb_describe_event(me, pb->active_set.poll_fds[i]); */
}
#endif /* PIKE_DEBUG */
 }
if (box->revents) {
next_fd:
/* Hook in the box on the fd_list. */
if (!box->next) {
IF_PD(fprintf(stderr,
"[%d]BACKEND[%d]: hooking in box for fd %d\n",
THR_NO, me->id, fd));
box->next = fd_list.next;
fd_list.next = box;
if (box->ref_obj) add_ref(box->ref_obj);
} else {
IF_PD(fprintf(stderr,
"[%d]BACKEND[%d]: fd %d already in list.\n",
THR_NO, me->id, fd));
}
}
}

/* Common code for all variants.
       *
       * Call callbacks for the active events.
       */
if (backend_call_active_callbacks(&fd_list, me)) {
CALL_AND_UNSET_ONERROR(free_fd_list);
goto backend_round_done;
}

CALL_AND_UNSET_ONERROR(free_fd_list);

/* Must be up-to-date for backend_do_call_outs. */
INVALIDATE_CURRENT_TIME();
}else{
switch(errno)
{
#ifdef __NT__
 default:
Pike_fatal("Error in backend %d\n",errno);
break;
#endif
 
case EINVAL:
Pike_fatal("Invalid timeout to select().\n");
break;

#ifdef WSAEINTR
 case WSAEINTR:
#endif
 case EINTR: /* ignore */
break;

#ifdef WSAEBADF
 case WSAEBADF:
#endif
#ifdef ENOTSOCK
 case ENOTSOCK:
#endif
#ifdef WSAENOTSOCK
 case WSAENOTSOCK:
#endif
 case EBADF:
/* TODO: Fix poll version! */
break;

}
}

{
int call_outs_called =
backend_do_call_outs(me); /* Will update current_time after calls. */
if (call_outs_called)
done_something = 1;
if (call_outs_called < 0)
goto backend_round_done;
}

call_callback(&me->backend_callbacks, NULL);

backend_round_done:

#ifdef PIKE_THREADS
 me->done_counter += done_something;

co_broadcast(&me->backend_signal);
#endif

CALL_AND_UNSET_ONERROR (uwp);

low_backend_round_done:
if (done_something <= 0)
timeout->tv_sec = -1;
else {
struct timeval now;
INACCURATE_GETTIMEOFDAY(&now);
timeout->tv_sec = now.tv_sec;
timeout->tv_usec = now.tv_usec;
my_subtract_timeval (timeout, &start_time);
}
}

/*! @decl float|int(0..0) `()(void|float|int(0..0) sleep_time)
   *!   Perform one pass through the backend.
   *!
   *!   Calls any outstanding call-outs and non-blocking I/O
   *!   callbacks that are registred in this backend object.
   *!
   *! @param sleep_time
   *!   Wait at most @[sleep_time] seconds. The default when
   *!   unspecified or the integer @expr{0@} is no time limit.
   *!
   *! @returns
   *!   If the backend did call any callbacks or call outs then the
   *!   time spent in the backend is returned as a float. Otherwise
   *!   the integer @expr{0@} is returned.
   *!
   *! @seealso
   *!   @[Pike.DefaultBackend], @[main()]
   */
#define f_PollBackend_cq__backtick_28_29_defined

#ifdef f_PollBackend_cq__backtick_28_29_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_PollBackend_cq__backtick_28_29_fun_num = 0;

#endif /* f_PollBackend_cq__backtick_28_29_fun_num_used */
DEFAULT_CMOD_STORAGE void f_PollBackend_cq__backtick_28_29(INT32 args) {
#line 5054 "/Users/hww3/devel/pike/src/backend.cmod"
struct svalue * sleep_time;
#line 5054 "/Users/hww3/devel/pike/src/backend.cmod"
if(args > 1) wrong_number_of_args_error("`()",args,1);
#line 5054 "/Users/hww3/devel/pike/src/backend.cmod"
if ((args > 0) &&
    ((TYPEOF(Pike_sp[0-args]) != PIKE_T_INT) ||
     (SUBTYPEOF(Pike_sp[0-args]) != NUMBER_UNDEFINED))) {
#line 5054 "/Users/hww3/devel/pike/src/backend.cmod"
sleep_time=Pike_sp+0-args; dmalloc_touch_svalue(Pike_sp+0-args);
#line 5054 "/Users/hww3/devel/pike/src/backend.cmod"
} else sleep_time = NULL;
{
struct timeval timeout; /* Got correct gcc warning on timeout.tv_usec. */

if (sleep_time && TYPEOF(*sleep_time) == PIKE_T_FLOAT) {
timeout.tv_sec = (long) floor (sleep_time->u.float_number);
timeout.tv_usec =
(long) ((sleep_time->u.float_number - timeout.tv_sec) * 1e6);
}
else if (sleep_time && TYPEOF(*sleep_time) == T_INT &&
sleep_time->u.integer) {
SIMPLE_BAD_ARG_ERROR("`()", 1, "float|int(0..0)");
}
else
{
timeout.tv_sec = -1;
timeout.tv_usec = 0;
}

pb_low_backend_once(THIS, &timeout);

pop_n_elems (args);
if (timeout.tv_sec < 0)
push_int (0);
else
push_float (DO_NOT_WARN ((FLOAT_TYPE)
(DO_NOT_WARN ((double) timeout.tv_sec) +
DO_NOT_WARN ((double) timeout.tv_usec) / 1e6)));
}

}

#undef extra_PollBackend_defined
#define extra_PollBackend_defined

#undef internal_init_PollBackend_defined
#define internal_init_PollBackend_defined

#undef PollBackend_event_handler_defined
#define PollBackend_event_handler_defined
static void init_PollBackend_struct(void)
#line 5102 "/Users/hww3/devel/pike/src/backend.cmod"
{
struct Backend_struct *me =
THIS->backend = (struct Backend_struct *)(((char *)THIS) + pb_offset);

IF_PD (fprintf (stderr, "[%d]BACKEND[%d]: init generic\n",
THR_NO, me->id));

#ifdef PIKE_DEBUG
 me->debug_handler = (debug_handler_fn *) pb_backend_do_debug;
#endif
 me->update_fd_set_handler = (update_fd_set_handler_fn *) pb_update_fd_set;
me->handler_data = THIS;

THIS->set.poll_fds=0;
THIS->set.poll_fd_size=0;
THIS->set.num_in_poll=0;

THIS->active_set.poll_fds=0;
THIS->active_set.poll_fd_size=0;
THIS->active_set.num_in_poll=0;
}


#undef internal_exit_PollBackend_defined
#define internal_exit_PollBackend_defined

#undef PollBackend_event_handler_defined
#define PollBackend_event_handler_defined
static void exit_PollBackend_struct(void)
#line 5126 "/Users/hww3/devel/pike/src/backend.cmod"
{
struct Backend_struct *me = THIS->backend;
int e;

IF_PD (fprintf (stderr, "[%d]BACKEND[%d]: exit generic backend\n",
THR_NO, me->id));

if (THIS->set.poll_fds) {
free(THIS->set.poll_fds);
THIS->set.poll_fds = NULL;
THIS->set.poll_fd_size = 0;
THIS->set.num_in_poll = 0;
}
if (THIS->active_set.poll_fds) {
free(THIS->active_set.poll_fds);
THIS->active_set.poll_fds = NULL;
THIS->active_set.poll_fd_size = 0;
THIS->active_set.num_in_poll = 0;
}
}

#ifdef PollBackend_event_handler_defined
static void PollBackend_event_handler(int ev) {
  switch(ev) {

#ifdef internal_init_PollBackend_defined
  case PROG_EVENT_INIT: init_PollBackend_struct(); break;

#endif /* internal_init_PollBackend_defined */

#ifdef internal_exit_PollBackend_defined
  case PROG_EVENT_EXIT: exit_PollBackend_struct(); break;

#endif /* internal_exit_PollBackend_defined */
  default: break; 
  }
}

#endif /* PollBackend_event_handler_defined */
/*! @endclass
 */

#line 5151 "/Users/hww3/devel/pike/src/backend.cmod"
#else /* HAVE_POLL */
/*! @class SelectBackend
 *! @inherit __Backend
 *!
 *! Backend based on the classic @tt{select(2)@} system call from BSD.
 */

#undef class_SelectBackend_defined
#define class_SelectBackend_defined
DEFAULT_CMOD_STORAGE struct program *SelectBackend_program=NULL;

#ifdef SelectBackend_program_fun_num_used
DEFAULT_CMOD_STORAGE int SelectBackend_program_fun_num=-1;
#endif /* SelectBackend_program_fun_num_used */

#undef inherit_Backend_SelectBackend_defined
#define inherit_Backend_SelectBackend_defined
#line 5159 "/Users/hww3/devel/pike/src/backend.cmod"
static int SelectBackend_Backend_inh_num = -1;
#line 5159 "/Users/hww3/devel/pike/src/backend.cmod"
static int SelectBackend_Backend_inh_offset = -1;
#line 5161 "/Users/hww3/devel/pike/src/backend.cmod"
/* Helpers to find the above inherit. */
static ptrdiff_t sb_offset = 0;

#undef var_backend_SelectBackend_defined
#define var_backend_SelectBackend_defined
#line 5165 "/Users/hww3/devel/pike/src/backend.cmod"
/* 
   * POLL/SELECT fd sets
   */

#undef var_set_SelectBackend_defined
#define var_set_SelectBackend_defined

#undef var_active_set_SelectBackend_defined
#define var_active_set_SelectBackend_defined

#undef THIS
#define THIS ((struct SelectBackend_struct *)(Pike_interpreter.frame_pointer->current_storage))

#undef THIS_SELECTBACKEND
#define THIS_SELECTBACKEND ((struct SelectBackend_struct *)(Pike_interpreter.frame_pointer->current_storage))

#undef OBJ2_SELECTBACKEND
#define OBJ2_SELECTBACKEND(o) ((struct SelectBackend_struct *)(o->storage+SelectBackend_storage_offset))

#undef GET_SELECTBACKEND_STORAGE
#define GET_SELECTBACKEND_STORAGE(o) ((struct SelectBackend_struct *)(o->storage+SelectBackend_storage_offset)
static ptrdiff_t SelectBackend_storage_offset;
struct SelectBackend_struct {

#ifdef var_backend_SelectBackend_defined
#line 5163 "/Users/hww3/devel/pike/src/backend.cmod"
struct Backend_struct *backend;
#endif /* var_backend_SelectBackend_defined */

#ifdef var_set_SelectBackend_defined
#line 5168 "/Users/hww3/devel/pike/src/backend.cmod"
struct sb_selectors set;
#endif /* var_set_SelectBackend_defined */

#ifdef var_active_set_SelectBackend_defined
#line 5169 "/Users/hww3/devel/pike/src/backend.cmod"
struct sb_active_selectors active_set;
#endif /* var_active_set_SelectBackend_defined */
};
#ifdef PIKE_DEBUG
/* Ensure the struct is used in a variable declaration, or else gdb might not see it. */
static struct SelectBackend_struct *SelectBackend_gdb_dummy_ptr;
#endif
#line 5173 "/Users/hww3/devel/pike/src/backend.cmod"
/*
   * FD set handling
   */

static void sb_update_fd_set (struct Backend_struct *me,
struct SelectBackend_struct *sb, int fd,
int old_events, int new_events)
{
int changed_events = old_events ^ new_events;

IF_PD(fprintf (stderr,
"[%d]BACKEND[%d]: sb_update_fd_set(.., %d, %d, %d):\n",
THR_NO, me->id, fd, old_events, new_events));


if (changed_events) {
if (changed_events & PIKE_BIT_FD_READ) {
if (new_events & PIKE_BIT_FD_READ) {
sb_MY_FD_SET(&sb->set, fd, MY_READSET);
/* Got to enable the exception set to get errors (at least
	   * according to POSIX). */
sb_MY_FD_SET(&sb->set, fd, MY_EXCEPTSET);
}
else {
sb_MY_FD_CLR(&sb->set, fd, MY_READSET);
if (!(new_events & PIKE_BIT_FD_READ_OOB) &&
!(new_events & PIKE_BIT_FD_WRITE))
/* Exceptions might cause calls to read, read_oob and write. */
sb_MY_FD_CLR(&sb->set, fd, MY_EXCEPTSET);
}
}

if (changed_events & PIKE_BIT_FD_READ_OOB) {
if (new_events & PIKE_BIT_FD_READ_OOB)
sb_MY_FD_SET(&sb->set, fd, MY_EXCEPTSET);
else {
if (!(new_events & PIKE_BIT_FD_READ)) {
if (!(new_events & PIKE_BIT_FD_WRITE))
/* Exceptions might cause calls to read, read_oob and write. */
sb_MY_FD_CLR(&sb->set, fd, MY_EXCEPTSET);
}
}
}

if (changed_events & PIKE_BIT_FD_WRITE) {
if (new_events & PIKE_BIT_FD_WRITE) {
sb_MY_FD_SET(&sb->set, fd, MY_WRITESET);
/* Got to enable the exception set to get errors (at least
	   * according to POSIX). */
sb_MY_FD_SET(&sb->set, fd, MY_EXCEPTSET);
}
else {
if (!(new_events & PIKE_BIT_FD_WRITE_OOB)) {
sb_MY_FD_CLR(&sb->set, fd, MY_WRITESET);
if (!(new_events & PIKE_BIT_FD_READ) &&
!(new_events & PIKE_BIT_FD_READ_OOB))
/* Exceptions might cause calls to read, read_oob and write. */
sb_MY_FD_CLR(&sb->set, fd, MY_EXCEPTSET);
}
}
}

if (changed_events & PIKE_BIT_FD_WRITE_OOB) {
if (new_events & PIKE_BIT_FD_WRITE_OOB)
sb_MY_FD_SET(&sb->set, fd, MY_WRITESET);
else {
if (!(new_events & PIKE_BIT_FD_WRITE)) {
sb_MY_FD_CLR(&sb->set, fd, MY_WRITESET);
}
}
}

if (new_events & ~old_events)
/* New events were added. */
backend_wake_up_backend (me);
}
}

#ifdef PIKE_DEBUG

static void sb_backend_do_debug(struct Backend_struct *me,
struct SelectBackend_struct *sb)
{
int e;
PIKE_STAT_T tmp;

/* FIXME: OOB? */
for(e=0;e<=sb->set.max_fd;e++)
{
if(my_FD_ISSET(e, sb->set.sets + MY_READSET)
|| my_FD_ISSET(e, sb->set.sets + MY_WRITESET)
|| my_FD_ISSET(e, sb->set.sets + MY_EXCEPTSET)
)
{
int ret;

if (e >= fd_map_size || fd_map[e] != me)
Pike_fatal("Unmapped fd %d in select set.\n", e);

do {
ret = fd_fstat(e, &tmp);
/* FIXME: Perhaps do check_threads_etc() here? */
}while(ret < 0 && errno == EINTR);

if(ret<0)
{
switch(errno)
{
case EBADF:
Pike_fatal("Backend filedescriptor %d is bad.\n",e);
break;
case ENOENT:
Pike_fatal("Backend filedescriptor %d is not.\n",e);
break;
}
}
}
}
}

#endif	/* PIKE_DEBUG */

/* A negative tv_sec in timeout turns it off. If it ran until the
   * timeout without calling any callbacks or call outs (except those
   * on backend_callbacks) then tv_sec will be set to -1. Otherwise it
   * will be set to the time spent. */
static void sb_low_backend_once(struct SelectBackend_struct *sb,
struct timeval *timeout)
{
ONERROR uwp;
int i, done_something = 0;
struct timeval start_time = *timeout;
struct Backend_struct *me = sb->backend;
#ifdef DECLARE_POLL_EXTRAS
 /* Declare any extra variables needed by MY_POLL(). */
DECLARE_POLL_EXTRAS;
#endif /* DECLARE_POLL_EXTRAS */

if ((done_something =
low_backend_once_setup(sb->backend, &start_time, &uwp))) {
goto low_backend_round_done;
}

if (TYPEOF(me->before_callback) != T_INT)
call_backend_monitor_cb (me, &me->before_callback);

{
struct timeval poll_timeout;
struct timeval *next_timeout = &sb->backend->next_timeout;

me->may_need_wakeup = 1;

poll_timeout = *next_timeout;

sb_copy_selectors(& sb->active_set, &sb->set);

IF_PD(fprintf (stderr, "[%d]BACKEND[%d]: Doing poll on fds:\n",
THR_NO, me->id));

check_threads_etc();
THREADS_ALLOW();

/* Note: The arguments to MY_POLL may be evaluated multiple times. */
i = SB_SELECT(sb->active_set, poll_timeout);

IF_PD(fprintf(stderr, " => %d\n", i));

THREADS_DISALLOW();
check_threads_etc();
me->may_need_wakeup = 0;
INVALIDATE_CURRENT_TIME();
}

if (TYPEOF(me->after_callback) != T_INT)
call_backend_monitor_cb (me, &me->after_callback);

if (!i) {
/* Timeout */
} else if (i>0) {
int num_active = i;
struct fd_callback_box fd_list = {
me, NULL, &fd_list,
-1, 0, 0,
0, 0, NULL
};
struct fd_callback_box *box;
ONERROR free_fd_list;

SET_ONERROR(free_fd_list, do_free_fd_list, &fd_list);

done_something = 1;

for(i=0; i <= sb->active_set.max_fd; i++)
{
box = SAFE_GET_ACTIVE_BOX(me, i);
if (!box) continue;
check_box(box, i);

box->revents = 0;
box->flags = 0;

if(fd_FD_ISSET(i, sb->active_set.asets + MY_EXCEPTSET)) {
/* Check for errors. GNU libc says this isn't set on error, but
	   * POSIX does. FIXME: What bits will be set for errors on GNU
	   * systems, then? Should we always check for that? */
int err = 0;
ACCEPT_SIZE_T len = sizeof (err);
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: exception on %d\n",
THR_NO, me->id, i));
if (!getsockopt (i, SOL_SOCKET, SO_ERROR, (void *)&err, &len) &&
err) {
IF_PD (fprintf (stderr, "[%d]BACKEND[%d]: error on %d, error=%d\n",
THR_NO, me->id, i, err));
box->revents |= PIKE_BIT_FD_ERROR;
} else {
box->revents |= PIKE_BIT_FD_READ_OOB;
}
}

if(fd_FD_ISSET(i, sb->active_set.asets + MY_READSET)) {
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: read on %d\n",
THR_NO, me->id, i));
box->revents |= PIKE_BIT_FD_READ;
}

if(fd_FD_ISSET(i, sb->active_set.asets + MY_WRITESET)) {
IF_PD(fprintf(stderr, "[%d]BACKEND[%d]: write on %d\n",
THR_NO, me->id, i));
/* OOB can by BSD definition always be written, so if we can
	   * write normal data it's reasonable to assume OOB can be
	   * written too without too much risk of being thrown away. */
box->revents |= PIKE_BIT_FD_WRITE | PIKE_BIT_FD_WRITE_OOB;
}

if (box->revents) {
/* Hook in the box on the fd_list. */
if (!box->next) {
box->next = fd_list.next;
fd_list.next = box;
if (box->ref_obj) add_ref(box->ref_obj);
}
}
}

/* Common code for all variants.
       *
       * Call callbacks for the active events.
       */
if (backend_call_active_callbacks(&fd_list, me)) {
CALL_AND_UNSET_ONERROR(free_fd_list);
goto backend_round_done;
}

CALL_AND_UNSET_ONERROR(free_fd_list);

/* Must be up-to-date for backend_do_call_outs. */
INVALIDATE_CURRENT_TIME();
}else{
switch(errno)
{
#ifdef __NT__
 default:
Pike_fatal("Error in backend %d\n",errno);
break;
#endif
 
case EINVAL:
Pike_fatal("Invalid timeout to select().\n");
break;

#ifdef WSAEINTR
 case WSAEINTR:
#endif
 case EINTR: /* ignore */
break;

#ifdef WSAEBADF
 case WSAEBADF:
#endif
#ifdef ENOTSOCK
 case ENOTSOCK:
#endif
#ifdef WSAENOTSOCK
 case WSAENOTSOCK:
#endif
 case EBADF:
/* TODO: Fix poll version! */

sb_copy_selectors(&sb->active_set, &sb->set);

timeout->tv_usec=0;
timeout->tv_sec=0;
if(SB_SELECT(sb->active_set, *timeout) < 0)
{
switch(errno)
{
#ifdef WSAEBADF
 case WSAEBADF:
#endif
#ifdef ENOTSOCK
 case ENOTSOCK:
#endif
#ifdef WSAENOTSOCK
 case WSAENOTSOCK:
#endif
 case EBADF:
{
FOR_EACH_ACTIVE_FD_BOX (me, box) {
fd_FD_ZERO(sb->active_set.asets + MY_READSET);
fd_FD_ZERO(sb->active_set.asets + MY_WRITESET);
fd_FD_ZERO(sb->active_set.asets + MY_EXCEPTSET);

if(my_FD_ISSET(box->fd, sb->set.sets + MY_READSET))
fd_FD_SET(box->fd, sb->active_set.asets + MY_READSET);
if(my_FD_ISSET(box->fd, sb->set.sets + MY_WRITESET))
fd_FD_SET(box->fd, sb->active_set.asets + MY_WRITESET);
if(my_FD_ISSET(box->fd, sb->set.sets + MY_EXCEPTSET))
fd_FD_SET(box->fd, sb->active_set.asets + MY_EXCEPTSET);

timeout->tv_usec=0;
timeout->tv_sec=0;

if(SB_SELECT(sb->active_set, *timeout) < 0)
{
switch(errno)
{
#ifdef __NT__
 default:
#endif
 case EBADF:
#ifdef WSAEBADF
 case WSAEBADF:
#endif
#ifdef ENOTSOCK
 case ENOTSOCK:
#endif
#ifdef WSAENOTSOCK
 case WSAENOTSOCK:
#endif

#ifdef DEBUG_MALLOC
 debug_malloc_dump_fd(box->fd);
#endif
 Pike_fatal("Filedescriptor %d (%s) caused fatal error %d "
"in backend.\n",
box->fd, fd_info(box->fd), errno);

case EINTR:
break;
}
}
}
}
}
#ifdef _REENTRANT
 /* FIXME: Extra stderr messages should not be allowed.../Hubbe */
write_to_stderr("Bad filedescriptor to select().\n"
"fd closed in another thread?\n", 62);
#else /* !_REENTRANT */
 Pike_fatal("Bad filedescriptor to select().\n");
#endif /* _REENTRANT */
 }
break;

}
}

{
int call_outs_called =
backend_do_call_outs(me); /* Will update current_time after calls. */
if (call_outs_called)
done_something = 1;
if (call_outs_called < 0)
goto backend_round_done;
}

call_callback(&me->backend_callbacks, NULL);

backend_round_done:

#ifdef PIKE_THREADS
 me->done_counter += done_something;

co_broadcast(&me->backend_signal);
#endif

CALL_AND_UNSET_ONERROR (uwp);

low_backend_round_done:

if (done_something <= 0)
timeout->tv_sec = -1;
else {
struct timeval now;
INACCURATE_GETTIMEOFDAY(&now);
timeout->tv_sec = now.tv_sec;
timeout->tv_usec = now.tv_usec;
my_subtract_timeval (timeout, &start_time);
}
}

/*! @decl float|int(0..0) `()(void|float|int(0..0) sleep_time)
   *!   Perform one pass through the backend.
   *!
   *!   Calls any outstanding call-outs and non-blocking I/O
   *!   callbacks that are registred in this backend object.
   *!
   *! @param sleep_time
   *!   Wait at most @[sleep_time] seconds. The default when
   *!   unspecified or the integer @expr{0@} is no time limit.
   *!
   *! @returns
   *!   If the backend did call any callbacks or call outs then the
   *!   time spent in the backend is returned as a float. Otherwise
   *!   the integer @expr{0@} is returned.
   *!
   *! @seealso
   *!   @[Pike.DefaultBackend], @[main()]
   */
#define f_SelectBackend_cq__backtick_28_29_defined

#ifdef f_SelectBackend_cq__backtick_28_29_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_SelectBackend_cq__backtick_28_29_fun_num = 0;

#endif /* f_SelectBackend_cq__backtick_28_29_fun_num_used */
DEFAULT_CMOD_STORAGE void f_SelectBackend_cq__backtick_28_29(INT32 args) {
#line 5592 "/Users/hww3/devel/pike/src/backend.cmod"
struct svalue * sleep_time;
#line 5592 "/Users/hww3/devel/pike/src/backend.cmod"
if(args > 1) wrong_number_of_args_error("`()",args,1);
#line 5592 "/Users/hww3/devel/pike/src/backend.cmod"
if ((args > 0) &&
    ((TYPEOF(Pike_sp[0-args]) != PIKE_T_INT) ||
     (SUBTYPEOF(Pike_sp[0-args]) != NUMBER_UNDEFINED))) {
#line 5592 "/Users/hww3/devel/pike/src/backend.cmod"
sleep_time=Pike_sp+0-args; dmalloc_touch_svalue(Pike_sp+0-args);
#line 5592 "/Users/hww3/devel/pike/src/backend.cmod"
} else sleep_time = NULL;
{
struct timeval timeout; /* Got bogus gcc warning on timeout.tv_usec. */

if (sleep_time && TYPEOF(*sleep_time) == PIKE_T_FLOAT) {
timeout.tv_sec = (long) floor (sleep_time->u.float_number);
timeout.tv_usec =
(long) ((sleep_time->u.float_number - timeout.tv_sec) * 1e6);
}
else if (sleep_time && TYPEOF(*sleep_time) == T_INT &&
sleep_time->u.integer) {
SIMPLE_BAD_ARG_ERROR("`()", 1, "float|int(0..0)");
}
else
timeout.tv_sec = -1;

sb_low_backend_once(THIS, &timeout);

pop_n_elems (args);
if (timeout.tv_sec < 0)
push_int (0);
else
push_float (DO_NOT_WARN ((FLOAT_TYPE)
(DO_NOT_WARN ((double) timeout.tv_sec) +
DO_NOT_WARN ((double) timeout.tv_usec) / 1e6)));
}

}

#undef extra_SelectBackend_defined
#define extra_SelectBackend_defined

#undef internal_init_SelectBackend_defined
#define internal_init_SelectBackend_defined

#undef SelectBackend_event_handler_defined
#define SelectBackend_event_handler_defined
static void init_SelectBackend_struct(void)
#line 5626 "/Users/hww3/devel/pike/src/backend.cmod"
{
struct Backend_struct *me =
THIS->backend = (struct Backend_struct *)(((char *)THIS) + sb_offset);

IF_PD (fprintf (stderr, "[%d]BACKEND[%d]: init generic\n",
THR_NO, me->id));

#ifdef PIKE_DEBUG
 me->debug_handler = (debug_handler_fn *) sb_backend_do_debug;
#endif
 me->update_fd_set_handler = (update_fd_set_handler_fn *) sb_update_fd_set;
me->handler_data = THIS;

THIS->set.max_fd=0;
my_FD_ZERO(THIS->set.sets + MY_READSET);
my_FD_ZERO(THIS->set.sets + MY_WRITESET);
my_FD_ZERO(THIS->set.sets + MY_EXCEPTSET);
/* FIXME: Should there be something else here? */
/* me->set.num_fds=0; */
}


#undef internal_exit_SelectBackend_defined
#define internal_exit_SelectBackend_defined

#undef SelectBackend_event_handler_defined
#define SelectBackend_event_handler_defined
static void exit_SelectBackend_struct(void)
#line 5649 "/Users/hww3/devel/pike/src/backend.cmod"
{
struct Backend_struct *me = THIS->backend;
IF_PD (fprintf (stderr, "[%d]BACKEND[%d]: exit generic backend\n",
THR_NO, me->id));
}

#ifdef SelectBackend_event_handler_defined
static void SelectBackend_event_handler(int ev) {
  switch(ev) {

#ifdef internal_init_SelectBackend_defined
  case PROG_EVENT_INIT: init_SelectBackend_struct(); break;

#endif /* internal_init_SelectBackend_defined */

#ifdef internal_exit_SelectBackend_defined
  case PROG_EVENT_EXIT: exit_SelectBackend_struct(); break;

#endif /* internal_exit_SelectBackend_defined */
  default: break; 
  }
}

#endif /* SelectBackend_event_handler_defined */
/*! @endclass
 */
#line 5658 "/Users/hww3/devel/pike/src/backend.cmod"
#endif

/*! @module DefaultBackend
 *!   This is the @[Backend] object that files and call_outs are
 *!   handled by by default.
 *!
 *!   This is also the @[Backend] object that will be used if @[main()]
 *!   returns @expr{-1@}.
 *!
 *! @seealso
 *!   @[Backend], @[Stdio.File()->set_nonblocking()], @[call_out()]
 */

/*! @endmodule
 */

/*! @endmodule
 */

/*! @decl mixed call_out(function f, float|int delay, mixed ... args)
 *! @decl void _do_call_outs()
 *! @decl int find_call_out(function f)
 *! @decl int find_call_out(mixed id)
 *! @decl int remove_call_out(function f)
 *! @decl int remove_call_out(function id)
 *! @decl array(array) call_out_info()
 *!   These are aliases for the corresponding functions in
 *!   @[Pike.DefaultBackend].
 *!
 *! @seealso
 *!   @[Pike.Backend()->call_out()], @[Pike.Backend()->_do_call_outs()],
 *!   @[Pike.Backend()->find_call_out()], @[Pike.Backend()->remove_call_out()],
 *!   @[Pike.Backend()->call_out_info()]
 */

/* This doesn't need to be here */
/**
 * Fail-safe/paranoid function to write a block of data to stderr (aka fd 2).
 */
PMOD_EXPORT int write_to_stderr(char *a, size_t len)
{
#ifdef __NT__
 size_t e;
for(e=0;e<len;e++)
putc(a[e],stderr);
#else
 int nonblock=0;
size_t pos;
int tmp;

if(!len) return 1;

for(pos=0;pos<len;pos+=tmp)
{
tmp=write(2,a+pos,len-pos);
if(tmp<0)
{
tmp=0;
switch(errno)
{
#ifdef EWOULDBLOCK
 case EWOULDBLOCK:
nonblock=1;
set_nonblocking(2,0);
continue;
#endif
 
case EINTR:
check_threads_etc();
continue;
}
break;
}
}

if(nonblock)
set_nonblocking(2,1);

#endif
 return 1;
}

/**
 * Get the backend (if any) that an fd is associated with.
 */
PMOD_EXPORT struct object *get_backend_obj_for_fd (int fd)
{
struct Backend_struct *b = really_get_backend_for_fd (fd);
if (!b) return NULL;
return b->backend_obj;
}

/**
 * Associate an fd with a backend.
 */
PMOD_EXPORT void set_backend_for_fd (int fd, struct Backend_struct *new)
{
struct Backend_struct *old = get_backend_for_fd (fd);

IF_PD (fprintf (stderr, "Changing backend from %d to %d for fd %d\n",
old ? old->id : -1, new ? new->id : -1, fd));

if (!old)
low_set_backend_for_fd (fd, new);
else if (old != new) {
struct fd_callback_box *box = SAFE_GET_ACTIVE_BOX (old, fd);
if (box) {
if (new)
change_backend_for_box (box, new);
else {
int is_compat_box = box->callback == compat_box_dispatcher;
unhook_fd_callback_box (box);
if (is_compat_box)
really_free_compat_cb_box ((struct compat_cb_box *) box);
}
}
low_set_backend_for_fd (fd, new);
}
}

/* Compat stuff for old backend interface. */

struct compat_cb_box
{
struct fd_callback_box box; /* Must be first. */
file_callback read, write, read_oob, write_oob, fs_event;
void *read_data, *write_data, *read_oob_data, *write_oob_data, *fs_event_data;
int flags; /* fs event flags */
};

#undef DMALLOC_DESCRIBE_BLOCK
#define DMALLOC_DESCRIBE_BLOCK(X) do {					\
    fprintf (stderr, "  backend: %p, fd: %d, events: 0x%x\n",		\
	     X->box.backend, X->box.fd, X->box.events);			\
  } while (0)

static struct block_allocator compat_cb_allocator =
BA_INIT_PAGES(sizeof(struct compat_cb_box), 1);

static struct compat_cb_box * alloc_compat_cb_box(void) {
return ba_alloc(&compat_cb_allocator);
}

static void really_free_compat_cb_box(struct compat_cb_box * b) {
ba_free(&compat_cb_allocator, b);
}

void count_memory_in_compat_cb_boxs(size_t * n, size_t * s) {
ba_count_all(&compat_cb_allocator, n, s);
}

void free_all_compat_cb_box_blocks(void) {
ba_destroy(&compat_cb_allocator);
}

static int compat_box_dispatcher (struct fd_callback_box *box, int event)
{
struct compat_cb_box *cbox = (struct compat_cb_box *) box;
switch (event) {
case PIKE_FD_READ:
IF_PD (fprintf (stderr, "[%d]BACKEND[%d]: compat_box_dispatcher for "
"PIKE_FD_READ to %p %p\n", THR_NO,
cbox->box.backend->id, cbox->read, cbox->read_data));
return cbox->read (cbox->box.fd, cbox->read_data);
case PIKE_FD_WRITE:
IF_PD (fprintf (stderr, "[%d]BACKEND[%d]: compat_box_dispatcher for "
"PIKE_FD_WRITE to %p %p\n", THR_NO,
cbox->box.backend->id, cbox->write, cbox->write_data));
return cbox->write (cbox->box.fd, cbox->write_data);
case PIKE_FD_READ_OOB:
IF_PD (fprintf (stderr, "[%d]BACKEND[%d]: compat_box_dispatcher for "
"PIKE_FD_READ_OOB to %p %p\n", THR_NO,
cbox->box.backend->id, cbox->read_oob,
cbox->read_oob_data));
return cbox->read_oob (cbox->box.fd, cbox->read_oob_data);
case PIKE_FD_WRITE_OOB:
IF_PD (fprintf (stderr, "[%d]BACKEND[%d]: compat_box_dispatcher for "
"PIKE_FD_WRITE_OOB to %p %p\n", THR_NO,
cbox->box.backend->id, cbox->write_oob,
cbox->write_oob_data));
return cbox->write_oob (cbox->box.fd, cbox->write_oob_data);
case PIKE_FD_FS_EVENT:
IF_PD (fprintf (stderr, "[%d]BACKEND[%d]: compat_box_dispatcher for "
"PIKE_FD_FS_EVENT to %p %p\n", THR_NO,
cbox->box.backend->id, cbox->fs_event,
cbox->fs_event_data));
return cbox->fs_event (cbox->box.fd, cbox->fs_event_data);
default:
#ifdef PIKE_DEBUG
 Pike_fatal ("Unexpected event type %d.\n", event);
#endif
 return 0; /* To keep gcc happy. */
}
}

#define WRAP(CB, EVENT_BIT)						\
  void PIKE_CONCAT3(set_, CB, _callback)				\
       (int fd, file_callback cb, void *data)				\
  {									\
    struct Backend_struct *b = really_get_backend_for_fd (fd);		\
    struct fd_callback_box *box = SAFE_GET_ACTIVE_BOX (b, fd);		\
    struct compat_cb_box *cbox;						\
									\
    IF_PD (fprintf (stderr,						\
		    "[%d]BACKEND[%d]: set_" #CB "_callback (%d, %p, %p)\n", \
		    THR_NO, b->id, fd, cb, data));			\
									\
    if (box) {								\
      check_box (box, fd);						\
      DO_IF_DEBUG (							\
	if (box->callback != compat_box_dispatcher)			\
	  Pike_fatal ("Mixing old and new style "			\
		      "backend interfaces for fd %d.\n", fd);		\
      );								\
      cbox = (struct compat_cb_box *) box;				\
    }									\
    else {								\
      if (!cb) return;							\
      cbox = alloc_compat_cb_box();					\
      INIT_FD_CALLBACK_BOX (&cbox->box, b, NULL,			\
			    fd, 0, compat_box_dispatcher, 0);		\
    }									\
									\
    cbox->CB = cb;							\
    cbox->PIKE_CONCAT (CB, _data) = data;				\
									\
    if (cb)								\
      set_fd_callback_events (&cbox->box, cbox->box.events | EVENT_BIT, \
			      cbox->flags);				\
    else {								\
      set_fd_callback_events (&cbox->box, cbox->box.events & ~EVENT_BIT, \
			      cbox->flags);				\
      if (!cbox->box.events) {						\
	unhook_fd_callback_box (&cbox->box);				\
	really_free_compat_cb_box (cbox);				\
      }									\
    }									\
  }									\
  									\
  file_callback PIKE_CONCAT3(query_, CB, _callback) (int fd)		\
  {									\
    struct Backend_struct *b=get_backend_for_fd (fd);			\
    struct fd_callback_box *box;					\
    struct compat_cb_box *cbox;						\
									\
    if (!b) return NULL;						\
    if (!(box = SAFE_GET_ACTIVE_BOX (b, fd))) return NULL;		\
    check_box (box, fd);						\
    DO_IF_DEBUG (							\
      if (box->callback != compat_box_dispatcher)			\
	Pike_fatal ("Mixing old and new style "				\
		    "backend interfaces for fd %d.\n", fd);		\
    );									\
									\
    cbox = (struct compat_cb_box *) box;				\
    if (!(cbox->box.events & EVENT_BIT)) return NULL;			\
    return cbox->CB;							\
  }									\
  									\
  void *PIKE_CONCAT3(query_, CB, _callback_data) (int fd)		\
  {									\
    struct Backend_struct *b=get_backend_for_fd (fd);			\
    struct fd_callback_box *box;					\
    struct compat_cb_box *cbox;						\
									\
    if (!b) return NULL;						\
    if (!(box = SAFE_GET_ACTIVE_BOX (b, fd))) return NULL;		\
    check_box (box, fd);						\
    DO_IF_DEBUG (							\
      if (box->callback != compat_box_dispatcher)			\
	Pike_fatal ("Mixing old and new style "				\
		    "backend interfaces for fd %d.\n", fd);		\
    );									\
									\
    cbox = (struct compat_cb_box *) box;				\
    if (!(cbox->box.events & EVENT_BIT)) return NULL;			\
    return cbox->PIKE_CONCAT (CB, _data);				\
  }

#define WRAP2(CB, EVENT_BIT)						\
  void PIKE_CONCAT3(set_, CB, _callback)				\
       (int fd, file_callback cb, void *data, int flags)		\
  {									\
    struct Backend_struct *b = really_get_backend_for_fd (fd);		\
    struct fd_callback_box *box = SAFE_GET_ACTIVE_BOX (b, fd);		\
    struct compat_cb_box *cbox;						\
									\
    IF_PD (fprintf (stderr,						\
		    "[%d]BACKEND[%d]: set_" #CB "_callback (%d, %p, %p)\n", \
		    THR_NO, b->id, fd, cb, data));			\
									\
    if (box) {								\
      check_box (box, fd);						\
      DO_IF_DEBUG (							\
	if (box->callback != compat_box_dispatcher)			\
	  Pike_fatal ("Mixing old and new style "			\
		      "backend interfaces for fd %d.\n", fd);		\
      );								\
      cbox = (struct compat_cb_box *) box;				\
    }									\
    else {								\
      if (!cb) return;							\
      cbox = alloc_compat_cb_box();					\
      INIT_FD_CALLBACK_BOX (&cbox->box, b, NULL,			\
			    fd, 0, compat_box_dispatcher, flags);	\
    }									\
									\
    cbox->CB = cb;							\
    cbox->PIKE_CONCAT (CB, _data) = data;				\
									\
    if (cb)								\
      set_fd_callback_events (&cbox->box, cbox->box.events | EVENT_BIT, \
			      cbox->flags);				\
    else {								\
      set_fd_callback_events (&cbox->box, cbox->box.events & ~EVENT_BIT, \
			      cbox->flags);				\
      if (!cbox->box.events) {						\
	unhook_fd_callback_box (&cbox->box);				\
	really_free_compat_cb_box (cbox);				\
      }									\
    }									\
  }									\
  									\
  file_callback PIKE_CONCAT3(query_, CB, _callback) (int fd)		\
  {									\
    struct Backend_struct *b=get_backend_for_fd (fd);			\
    struct fd_callback_box *box;					\
    struct compat_cb_box *cbox;						\
									\
    if (!b) return NULL;						\
    if (!(box = SAFE_GET_ACTIVE_BOX (b, fd))) return NULL;		\
    check_box (box, fd);						\
    DO_IF_DEBUG (							\
      if (box->callback != compat_box_dispatcher)			\
	Pike_fatal ("Mixing old and new style "				\
		    "backend interfaces for fd %d.\n", fd);		\
    );									\
									\
    cbox = (struct compat_cb_box *) box;				\
    if (!(cbox->box.events & EVENT_BIT)) return NULL;			\
    return cbox->CB;							\
  }									\
  									\
  void *PIKE_CONCAT3(query_, CB, _callback_data) (int fd)		\
  {									\
    struct Backend_struct *b=get_backend_for_fd (fd);			\
    struct fd_callback_box *box;					\
    struct compat_cb_box *cbox;						\
									\
    if (!b) return NULL;						\
    if (!(box = SAFE_GET_ACTIVE_BOX (b, fd))) return NULL;		\
    check_box (box, fd);						\
    DO_IF_DEBUG (							\
      if (box->callback != compat_box_dispatcher)			\
	Pike_fatal ("Mixing old and new style "				\
		    "backend interfaces for fd %d.\n", fd);		\
    );									\
									\
    cbox = (struct compat_cb_box *) box;				\
    if (!(cbox->box.events & EVENT_BIT)) return NULL;			\
    return cbox->PIKE_CONCAT (CB, _data);				\
  }

WRAP(read, PIKE_BIT_FD_READ)
WRAP(write, PIKE_BIT_FD_WRITE)
WRAP(read_oob, PIKE_BIT_FD_READ_OOB)
WRAP(write_oob, PIKE_BIT_FD_WRITE_OOB)
WRAP2(fs_event, PIKE_BIT_FD_FS_EVENT)

/**
 * Add a callback to be called by the default backend.
 */
PMOD_EXPORT struct callback *debug_add_backend_callback(callback_func call,
void *arg,
callback_func free_func)
{
return backend_debug_add_backend_callback(default_backend,
call,
arg,
free_func);
}

void wake_up_backend(void)
{
if(default_backend)
backend_wake_up_backend(default_backend);
}

void do_call_outs(void)
{
if(default_backend) {
INVALIDATE_CURRENT_TIME();
backend_do_call_outs(default_backend);
}
}

#ifdef PIKE_DEBUG
long do_debug_cycle=1;
long current_do_debug_cycle=0;
void do_debug(void)
{
extern void check_all_arrays(void);
extern void check_all_mappings(void);
extern void check_all_programs(void);
extern void check_all_objects(void);
extern void verify_shared_strings_tables(void);
extern void slow_check_stack(void);

if(current_do_debug_cycle) return;
current_do_debug_cycle=++do_debug_cycle;

if (d_flag > 2) {
verify_shared_strings_tables();
slow_check_stack();
check_all_arrays();
check_all_mappings();
check_all_programs();
check_all_objects();
}

call_callback(& do_debug_callbacks, 0);

if(default_backend)
backend_do_debug(default_backend);

if(d_flag>3) do_gc(NULL, 1);

current_do_debug_cycle=0;
}

/**
 * Assert that an fd is valid and not already in use by any backend.
 */
PMOD_EXPORT void debug_check_fd_not_in_use (int fd)
{
if (fd < 0) Pike_fatal ("Invalid fd: %d\n", fd);
if (fd < fd_map_size && fd_map[fd])
Pike_fatal ("fd %d already in use by backend %d.\n", fd, fd_map[fd]->id);
}

#endif /* PIKE_DEBUG */

static struct callback *mem_callback;

void init_backend(void)
{
IF_PD(fprintf(stderr, "BACKEND: Init compat callback boxes...\n"));
IF_PD(fprintf(stderr, "BACKEND: INIT...\n"));

#ifdef module_strings_declared
module_strings[0] = 
  make_shared_binary_string("Thread.Thread",
                            CONSTANT_STRLEN("Thread.Thread"));
#endif

#ifdef CMOD_MAP_PROGRAM_IDS_DEFINED
{ int i=0;
#ifndef tObjImpl_THREAD_THREAD
# define tObjImpl_THREAD_THREAD "\3\0\177\0\0\a"
{
   struct program *tmp = resolve_program(module_strings[0] /* "Thread.Thread" */);
   if( tmp ) {
      ___cmod_ext_used[i].from = 7;
      ___cmod_ext_used[i].to = tmp->id;
      i++;
   }
}
#endif /* tObjImpl_THREAD_THREAD */
}
set_program_id_to_id( ___cmod_map_program_ids );

#endif /* CMOD_MAP_PROGRAM_IDS_DEFINED */

#ifdef class_Backend_defined

#ifdef PROG_BACKEND_ID
#line 275 "/Users/hww3/devel/pike/src/backend.cmod"
  START_NEW_PROGRAM_ID(BACKEND);
#else
#line 275 "/Users/hww3/devel/pike/src/backend.cmod"
  start_new_program();

#endif /* PROG_BACKEND_ID */
#line 275 "/Users/hww3/devel/pike/src/backend.cmod"
  Backend_program = Pike_compiler->new_program;

#ifndef tObjImpl_BACKEND

#undef tObjIs_BACKEND
#define tObjIs_BACKEND "\3\1\177\0\0\2"

#undef tObjImpl_BACKEND
#define tObjImpl_BACKEND "\3\0\177\0\0\2"

#endif /* tObjImpl_BACKEND */

#ifdef THIS_BACKEND
  Backend_storage_offset = ADD_STORAGE(struct Backend_struct);
#endif /* THIS_BACKEND */

#ifdef var_before_callback_Backend_defined
  PIKE_MAP_VARIABLE("before_callback", Backend_storage_offset + OFFSETOF(Backend_struct, before_callback),
                    tFunc(tName("Backend", tObjImpl_BACKEND),tVoid), PIKE_T_MIXED, 0);
#endif /* var_before_callback_Backend_defined */

#ifdef var_after_callback_Backend_defined
  PIKE_MAP_VARIABLE("after_callback", Backend_storage_offset + OFFSETOF(Backend_struct, after_callback),
                    tFunc(tName("Backend", tObjImpl_BACKEND),tVoid), PIKE_T_MIXED, 0);
#endif /* var_after_callback_Backend_defined */

#ifdef class_Backend_CallOut_defined

#ifdef PROG_BACKEND_CALLOUT_ID
#line 474 "/Users/hww3/devel/pike/src/backend.cmod"
  START_NEW_PROGRAM_ID(BACKEND_CALLOUT);
#else
#line 474 "/Users/hww3/devel/pike/src/backend.cmod"
  start_new_program();

#endif /* PROG_BACKEND_CALLOUT_ID */
#line 474 "/Users/hww3/devel/pike/src/backend.cmod"
  Backend_CallOut_program = Pike_compiler->new_program;

#ifndef tObjImpl_BACKEND_CALLOUT

#undef tObjIs_BACKEND_CALLOUT
#define tObjIs_BACKEND_CALLOUT "\3\1\177\0\0\3"

#undef tObjImpl_BACKEND_CALLOUT
#define tObjImpl_BACKEND_CALLOUT "\3\0\177\0\0\3"

#endif /* tObjImpl_BACKEND_CALLOUT */

#ifdef THIS_BACKEND_CALLOUT
  Backend_CallOut_storage_offset = ADD_STORAGE(struct Backend_CallOut_struct);
#endif /* THIS_BACKEND_CALLOUT */

#ifdef var_args_Backend_CallOut_defined
  PIKE_MAP_VARIABLE("args", Backend_CallOut_storage_offset + OFFSETOF(Backend_CallOut_struct, args),
                    tArray, PIKE_T_ARRAY, ID_STATIC);
#endif /* var_args_Backend_CallOut_defined */

#ifdef Backend_CallOut_event_handler_defined
  pike_set_prog_event_callback(Backend_CallOut_event_handler);

#ifndef Backend_CallOut_gc_live_obj
  Pike_compiler->new_program->flags &= ~PROGRAM_LIVE_OBJ;

#endif /* Backend_CallOut_gc_live_obj */

#endif /* Backend_CallOut_event_handler_defined */

#ifdef f_Backend_CallOut_create_defined

#ifdef f_Backend_CallOut_create_fun_num_used
  f_Backend_CallOut_create_fun_num =
#endif /* f_Backend_CallOut_create_fun_num_used */
#line 719 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("create", f_Backend_CallOut_create, tFuncV(tOr("\10\200\0\0\0\177\377\377\377",tFloat) tMix,tMix,tVoid), ID_PROTECTED, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_Backend_CallOut_create_defined */
#line 475 "/Users/hww3/devel/pike/src/backend.cmod"
  Pike_compiler->new_program->flags |= PROGRAM_USES_PARENT|PROGRAM_NEEDS_PARENT;
#line 474 "/Users/hww3/devel/pike/src/backend.cmod"
  Backend_CallOut_program=end_program();
#line 474 "/Users/hww3/devel/pike/src/backend.cmod"
#ifdef Backend_CallOut_program_fun_num_used
Backend_CallOut_program_fun_num=
#endif
 add_program_constant("CallOut",Backend_CallOut_program,ID_PROTECTED|ID_PRIVATE|ID_USED);

#endif /* class_Backend_CallOut_defined */

#ifdef Backend_event_handler_defined
  pike_set_prog_event_callback(Backend_event_handler);

#ifndef Backend_gc_live_obj
  Pike_compiler->new_program->flags &= ~PROGRAM_LIVE_OBJ;

#endif /* Backend_gc_live_obj */

#endif /* Backend_event_handler_defined */

#ifdef f_Backend_get_stats_defined

#ifdef f_Backend_get_stats_fun_num_used
  f_Backend_get_stats_fun_num =
#endif /* f_Backend_get_stats_fun_num_used */
#line 908 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("get_stats", f_Backend_get_stats, tFunc(tNone,tMap(tStr,"\10\200\0\0\0\177\377\377\377")), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_Backend_get_stats_defined */

#ifdef f_Backend_call_out_defined

#ifdef f_Backend_call_out_fun_num_used
  f_Backend_call_out_fun_num =
#endif /* f_Backend_call_out_fun_num_used */
#line 950 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("call_out", f_Backend_call_out, tFuncV(tMix tOr("\10\200\0\0\0\177\377\377\377",tFloat),tMix,tArray), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_Backend_call_out_defined */

#ifdef f_Backend_cq__do_call_outs_defined

#ifdef f_Backend_cq__do_call_outs_fun_num_used
  f_Backend_cq__do_call_outs_fun_num =
#endif /* f_Backend_cq__do_call_outs_fun_num_used */
#line 1205 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("_do_call_outs", f_Backend_cq__do_call_outs, tFunc(tNone,"\10\200\0\0\0\177\377\377\377"), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_Backend_cq__do_call_outs_defined */

#ifdef f_Backend_find_call_out_defined

#ifdef f_Backend_find_call_out_fun_num_used
  f_Backend_find_call_out_fun_num =
#endif /* f_Backend_find_call_out_fun_num_used */
#line 1231 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("find_call_out", f_Backend_find_call_out, tFunc(tOr(tFuncV(tNone,tMix,tAny),tMix),"\10\200\0\0\0\177\377\377\377"), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_Backend_find_call_out_defined */

#ifdef f_Backend_remove_call_out_defined

#ifdef f_Backend_remove_call_out_fun_num_used
  f_Backend_remove_call_out_fun_num =
#endif /* f_Backend_remove_call_out_fun_num_used */
#line 1283 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("remove_call_out", f_Backend_remove_call_out, tFunc(tOr(tFuncV(tNone,tMix,tAny),tMix),"\10\200\0\0\0\177\377\377\377"), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_Backend_remove_call_out_defined */

#ifdef f_Backend_call_out_info_defined

#ifdef f_Backend_call_out_info_fun_num_used
  f_Backend_call_out_info_fun_num =
#endif /* f_Backend_call_out_info_fun_num_used */
#line 1410 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("call_out_info", f_Backend_call_out_info, tFunc(tNone,tArr(tArray)), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_Backend_call_out_info_defined */

#ifdef f_Backend_cq__backtick_28_29_defined

#ifdef f_Backend_cq__backtick_28_29_fun_num_used
  f_Backend_cq__backtick_28_29_fun_num =
#endif /* f_Backend_cq__backtick_28_29_fun_num_used */
#line 1981 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("`()", NULL, tFunc(tOr3(tVoid,tFloat,"\10\0\0\0\0\0\0\0\0"),tOr(tFloat,"\10\0\0\0\0\0\0\0\0")), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_Backend_cq__backtick_28_29_defined */

#ifdef f_Backend_executing_thread_defined

#ifdef f_Backend_executing_thread_fun_num_used
  f_Backend_executing_thread_fun_num =
#endif /* f_Backend_executing_thread_fun_num_used */
#line 2004 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("executing_thread", f_Backend_executing_thread, tFunc(tNone,tOr(tName("Thread.Thread", tObjImpl_THREAD_THREAD),"\10\0\0\0\0\0\0\0\1")), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_Backend_executing_thread_defined */

#ifdef f_Backend_add_file_defined

#ifdef f_Backend_add_file_fun_num_used
  f_Backend_add_file_fun_num =
#endif /* f_Backend_add_file_fun_num_used */
#line 2033 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("add_file", f_Backend_add_file, tFunc(tObj,tVoid), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_Backend_add_file_defined */

#ifdef f_Backend_id_defined

#ifdef f_Backend_id_fun_num_used
  f_Backend_id_fun_num =
#endif /* f_Backend_id_fun_num_used */
#line 2046 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("id", f_Backend_id, tFunc(tNone,"\10\200\0\0\0\177\377\377\377"), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_Backend_id_defined */

#ifdef f_Backend_cq__sprintf_defined

#ifdef f_Backend_cq__sprintf_fun_num_used
  f_Backend_cq__sprintf_fun_num =
#endif /* f_Backend_cq__sprintf_fun_num_used */
#line 2051 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("_sprintf", f_Backend_cq__sprintf, tFunc("\10\200\0\0\0\177\377\377\377" tMapping,tStr), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_Backend_cq__sprintf_defined */

#ifdef f_Backend_create_defined

#ifdef f_Backend_create_fun_num_used
  f_Backend_create_fun_num =
#endif /* f_Backend_create_fun_num_used */
#line 2610 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("create", f_Backend_create, tFunc(tNone,tVoid), ID_PROTECTED, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_Backend_create_defined */
#line 275 "/Users/hww3/devel/pike/src/backend.cmod"
  Backend_program=end_program();
#line 275 "/Users/hww3/devel/pike/src/backend.cmod"
#ifdef Backend_program_fun_num_used
Backend_program_fun_num=
#endif
 add_program_constant("Backend",Backend_program,0);

#endif /* class_Backend_defined */

#ifdef class_PollDeviceBackend_defined

#ifdef PROG_POLLDEVICEBACKEND_ID
#line 3267 "/Users/hww3/devel/pike/src/backend.cmod"
  START_NEW_PROGRAM_ID(POLLDEVICEBACKEND);
#else
#line 3267 "/Users/hww3/devel/pike/src/backend.cmod"
  start_new_program();

#endif /* PROG_POLLDEVICEBACKEND_ID */
#line 3267 "/Users/hww3/devel/pike/src/backend.cmod"
  PollDeviceBackend_program = Pike_compiler->new_program;

#ifndef tObjImpl_POLLDEVICEBACKEND

#undef tObjIs_POLLDEVICEBACKEND
#define tObjIs_POLLDEVICEBACKEND "\3\1\177\0\0\4"

#undef tObjImpl_POLLDEVICEBACKEND
#define tObjImpl_POLLDEVICEBACKEND "\3\0\177\0\0\4"

#endif /* tObjImpl_POLLDEVICEBACKEND */

#ifdef THIS_POLLDEVICEBACKEND
  PollDeviceBackend_storage_offset = ADD_STORAGE(struct PollDeviceBackend_struct);
#endif /* THIS_POLLDEVICEBACKEND */

#ifdef inherit_Backend_PollDeviceBackend_defined
#line 3269 "/Users/hww3/devel/pike/src/backend.cmod"
  PollDeviceBackend_Backend_inh_num = Pike_compiler->new_program->num_inherits;
#line 3269 "/Users/hww3/devel/pike/src/backend.cmod"
  low_inherit(Backend_program, NULL, -1, 0, 0, NULL);
#line 3269 "/Users/hww3/devel/pike/src/backend.cmod"
  PollDeviceBackend_Backend_inh_offset = Pike_compiler->new_program->inherits[PollDeviceBackend_Backend_inh_num].identifier_level;

#endif /* inherit_Backend_PollDeviceBackend_defined */

#ifdef extra_PollDeviceBackend_defined
#line 4422 "/Users/hww3/devel/pike/src/backend.cmod"
{
pdb_offset = Pike_compiler->new_program->inherits[1].storage_offset -
Pike_compiler->new_program->inherits[0].storage_offset;

/* /dev/poll and kqueue fds get invalidated at fork. */
dmalloc_accept_leak(add_to_callback(&fork_child_callback,
reopen_all_pdb_backends, NULL, NULL));

#ifdef BACKEND_USES_CFRUNLOOP
 add_integer_constant("HAVE_CORE_FOUNDATION", 1, 0);
#endif /* BACKEND_USES_CFRUNLOOP */

#ifdef BACKEND_USES_KQUEUE
 add_integer_constant("HAVE_KQUEUE", 1, 0);
#endif /* BACKEND_USES_KQUEUE */

}


#endif /* extra_PollDeviceBackend_defined */

#ifdef PollDeviceBackend_event_handler_defined
  pike_set_prog_event_callback(PollDeviceBackend_event_handler);

#ifndef PollDeviceBackend_gc_live_obj
  Pike_compiler->new_program->flags &= ~PROGRAM_LIVE_OBJ;

#endif /* PollDeviceBackend_gc_live_obj */

#endif /* PollDeviceBackend_event_handler_defined */

#ifdef f_PollDeviceBackend_set_signal_event_callback_defined

#ifdef f_PollDeviceBackend_set_signal_event_callback_fun_num_used
  f_PollDeviceBackend_set_signal_event_callback_fun_num =
#endif /* f_PollDeviceBackend_set_signal_event_callback_fun_num_used */
#line 3311 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("set_signal_event_callback", f_PollDeviceBackend_set_signal_event_callback, tFunc("\10\200\0\0\0\177\377\377\377" tFuncV(tNone,tMix,tAny),tVoid), ID_OPTIONAL, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_PollDeviceBackend_set_signal_event_callback_defined */

#ifdef f_PollDeviceBackend_cq__backtick_28_29_defined

#ifdef f_PollDeviceBackend_cq__backtick_28_29_fun_num_used
  f_PollDeviceBackend_cq__backtick_28_29_fun_num =
#endif /* f_PollDeviceBackend_cq__backtick_28_29_fun_num_used */
#line 4297 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("`()", f_PollDeviceBackend_cq__backtick_28_29, tFunc(tOr3(tVoid,tFloat,"\10\0\0\0\0\0\0\0\0"),tOr(tFloat,"\10\0\0\0\0\0\0\0\0")), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_PollDeviceBackend_cq__backtick_28_29_defined */

#ifdef f_PollDeviceBackend_enable_core_foundation_defined

#ifdef f_PollDeviceBackend_enable_core_foundation_fun_num_used
  f_PollDeviceBackend_enable_core_foundation_fun_num =
#endif /* f_PollDeviceBackend_enable_core_foundation_fun_num_used */
#line 4340 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("enable_core_foundation", f_PollDeviceBackend_enable_core_foundation, tFunc("\10\200\0\0\0\177\377\377\377","\10\200\0\0\0\177\377\377\377"), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_PollDeviceBackend_enable_core_foundation_defined */

#ifdef f_PollDeviceBackend_query_core_foundation_enabled_defined

#ifdef f_PollDeviceBackend_query_core_foundation_enabled_fun_num_used
  f_PollDeviceBackend_query_core_foundation_enabled_fun_num =
#endif /* f_PollDeviceBackend_query_core_foundation_enabled_fun_num_used */
#line 4370 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("query_core_foundation_enabled", f_PollDeviceBackend_query_core_foundation_enabled, tFunc(tNone,"\10\200\0\0\0\177\377\377\377"), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_PollDeviceBackend_query_core_foundation_enabled_defined */

#ifdef f_PollDeviceBackend_enable_external_runloop_defined

#ifdef f_PollDeviceBackend_enable_external_runloop_fun_num_used
  f_PollDeviceBackend_enable_external_runloop_fun_num =
#endif /* f_PollDeviceBackend_enable_external_runloop_fun_num_used */
#line 4395 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("enable_external_runloop", f_PollDeviceBackend_enable_external_runloop, tFunc("\10\200\0\0\0\177\377\377\377","\10\200\0\0\0\177\377\377\377"), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_PollDeviceBackend_enable_external_runloop_defined */
#line 3267 "/Users/hww3/devel/pike/src/backend.cmod"
  PollDeviceBackend_program=end_program();
#line 3267 "/Users/hww3/devel/pike/src/backend.cmod"
#ifdef PollDeviceBackend_program_fun_num_used
PollDeviceBackend_program_fun_num=
#endif
 add_program_constant("PollDeviceBackend",PollDeviceBackend_program,0);

#endif /* class_PollDeviceBackend_defined */

#ifdef class_PollBackend_defined

#ifdef PROG_POLLBACKEND_ID
#line 4547 "/Users/hww3/devel/pike/src/backend.cmod"
  START_NEW_PROGRAM_ID(POLLBACKEND);
#else
#line 4547 "/Users/hww3/devel/pike/src/backend.cmod"
  start_new_program();

#endif /* PROG_POLLBACKEND_ID */
#line 4547 "/Users/hww3/devel/pike/src/backend.cmod"
  PollBackend_program = Pike_compiler->new_program;

#ifndef tObjImpl_POLLBACKEND

#undef tObjIs_POLLBACKEND
#define tObjIs_POLLBACKEND "\3\1\177\0\0\5"

#undef tObjImpl_POLLBACKEND
#define tObjImpl_POLLBACKEND "\3\0\177\0\0\5"

#endif /* tObjImpl_POLLBACKEND */

#ifdef THIS_POLLBACKEND
  PollBackend_storage_offset = ADD_STORAGE(struct PollBackend_struct);
#endif /* THIS_POLLBACKEND */

#ifdef inherit_Backend_PollBackend_defined
#line 4549 "/Users/hww3/devel/pike/src/backend.cmod"
  PollBackend_Backend_inh_num = Pike_compiler->new_program->num_inherits;
#line 4549 "/Users/hww3/devel/pike/src/backend.cmod"
  low_inherit(Backend_program, NULL, -1, 0, 0, NULL);
#line 4549 "/Users/hww3/devel/pike/src/backend.cmod"
  PollBackend_Backend_inh_offset = Pike_compiler->new_program->inherits[PollBackend_Backend_inh_num].identifier_level;

#endif /* inherit_Backend_PollBackend_defined */

#ifdef extra_PollBackend_defined
#line 5085 "/Users/hww3/devel/pike/src/backend.cmod"
{
pb_offset = Pike_compiler->new_program->inherits[1].storage_offset -
Pike_compiler->new_program->inherits[0].storage_offset;

IF_PD(fprintf(stderr,
"MY_POLLIN:       0x%04x\n"
"MY_POLLOUT:      0x%04x\n"
"MY_POLLEXCEPT:   0x%04x\n"
"MY_POLLRDBAND:   0x%04x\n"
"MY_POLLWREXCEPT: 0x%04x\n"
"MY_POLLWRBAND:   0x%04x\n",
MY_POLLIN, MY_POLLOUT,
MY_POLLEXCEPT, MY_POLLRDBAND,
MY_POLLWREXCEPT, MY_POLLWRBAND));
}


#endif /* extra_PollBackend_defined */

#ifdef PollBackend_event_handler_defined
  pike_set_prog_event_callback(PollBackend_event_handler);

#ifndef PollBackend_gc_live_obj
  Pike_compiler->new_program->flags &= ~PROGRAM_LIVE_OBJ;

#endif /* PollBackend_gc_live_obj */

#endif /* PollBackend_event_handler_defined */

#ifdef f_PollBackend_cq__backtick_28_29_defined

#ifdef f_PollBackend_cq__backtick_28_29_fun_num_used
  f_PollBackend_cq__backtick_28_29_fun_num =
#endif /* f_PollBackend_cq__backtick_28_29_fun_num_used */
#line 5054 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("`()", f_PollBackend_cq__backtick_28_29, tFunc(tOr3(tVoid,tFloat,"\10\0\0\0\0\0\0\0\0"),tOr(tFloat,"\10\0\0\0\0\0\0\0\0")), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_PollBackend_cq__backtick_28_29_defined */
#line 4547 "/Users/hww3/devel/pike/src/backend.cmod"
  PollBackend_program=end_program();
#line 4547 "/Users/hww3/devel/pike/src/backend.cmod"
#ifdef PollBackend_program_fun_num_used
PollBackend_program_fun_num=
#endif
 add_program_constant("PollBackend",PollBackend_program,0);

#endif /* class_PollBackend_defined */

#ifdef class_SelectBackend_defined

#ifdef PROG_SELECTBACKEND_ID
#line 5157 "/Users/hww3/devel/pike/src/backend.cmod"
  START_NEW_PROGRAM_ID(SELECTBACKEND);
#else
#line 5157 "/Users/hww3/devel/pike/src/backend.cmod"
  start_new_program();

#endif /* PROG_SELECTBACKEND_ID */
#line 5157 "/Users/hww3/devel/pike/src/backend.cmod"
  SelectBackend_program = Pike_compiler->new_program;

#ifndef tObjImpl_SELECTBACKEND

#undef tObjIs_SELECTBACKEND
#define tObjIs_SELECTBACKEND "\3\1\177\0\0\6"

#undef tObjImpl_SELECTBACKEND
#define tObjImpl_SELECTBACKEND "\3\0\177\0\0\6"

#endif /* tObjImpl_SELECTBACKEND */

#ifdef THIS_SELECTBACKEND
  SelectBackend_storage_offset = ADD_STORAGE(struct SelectBackend_struct);
#endif /* THIS_SELECTBACKEND */

#ifdef inherit_Backend_SelectBackend_defined
#line 5159 "/Users/hww3/devel/pike/src/backend.cmod"
  SelectBackend_Backend_inh_num = Pike_compiler->new_program->num_inherits;
#line 5159 "/Users/hww3/devel/pike/src/backend.cmod"
  low_inherit(Backend_program, NULL, -1, 0, 0, NULL);
#line 5159 "/Users/hww3/devel/pike/src/backend.cmod"
  SelectBackend_Backend_inh_offset = Pike_compiler->new_program->inherits[SelectBackend_Backend_inh_num].identifier_level;

#endif /* inherit_Backend_SelectBackend_defined */

#ifdef extra_SelectBackend_defined
#line 5620 "/Users/hww3/devel/pike/src/backend.cmod"
{
sb_offset = Pike_compiler->new_program->inherits[1].storage_offset -
Pike_compiler->new_program->inherits[0].storage_offset;
}


#endif /* extra_SelectBackend_defined */

#ifdef SelectBackend_event_handler_defined
  pike_set_prog_event_callback(SelectBackend_event_handler);

#ifndef SelectBackend_gc_live_obj
  Pike_compiler->new_program->flags &= ~PROGRAM_LIVE_OBJ;

#endif /* SelectBackend_gc_live_obj */

#endif /* SelectBackend_event_handler_defined */

#ifdef f_SelectBackend_cq__backtick_28_29_defined

#ifdef f_SelectBackend_cq__backtick_28_29_fun_num_used
  f_SelectBackend_cq__backtick_28_29_fun_num =
#endif /* f_SelectBackend_cq__backtick_28_29_fun_num_used */
#line 5592 "/Users/hww3/devel/pike/src/backend.cmod"
    ADD_FUNCTION2("`()", f_SelectBackend_cq__backtick_28_29, tFunc(tOr3(tVoid,tFloat,"\10\0\0\0\0\0\0\0\0"),tOr(tFloat,"\10\0\0\0\0\0\0\0\0")), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_SelectBackend_cq__backtick_28_29_defined */
#line 5157 "/Users/hww3/devel/pike/src/backend.cmod"
  SelectBackend_program=end_program();
#line 5157 "/Users/hww3/devel/pike/src/backend.cmod"
#ifdef SelectBackend_program_fun_num_used
SelectBackend_program_fun_num=
#endif
 add_program_constant("SelectBackend",SelectBackend_program,0);

#endif /* class_SelectBackend_defined */

#ifdef CMOD_MAP_PROGRAM_IDS_DEFINED
set_program_id_to_id( 0 );
#endif /* CMOD_MAP_PROGRAM_IDS_DEFINED */
#line 6106 "/Users/hww3/devel/pike/src/backend.cmod"
;
IF_PD(fprintf(stderr, "BACKEND: Creating default backend...\n"));
{
/* Select something suitable. */
#ifdef OPEN_POLL_DEVICE
 /* Note that creation of a poll device backend may fail. */
JMP_BUF recovery;
if (SETJMP(recovery)) {
#ifdef HAVE_POLL
 default_backend_obj = clone_object(PollBackend_program, 0);
#else
 default_backend_obj = clone_object(SelectBackend_program, 0);
#endif
 } else {
default_backend_obj = clone_object(PollDeviceBackend_program, 0);
}
UNSETJMP(recovery);
#elif defined(HAVE_POLL)
 default_backend_obj = clone_object(PollBackend_program, 0);
#else
 default_backend_obj = clone_object(SelectBackend_program, 0);
#endif
 default_backend = get_storage(default_backend_obj, Backend_program);

mem_callback=add_memory_usage_callback(count_memory_in_call_outs,0,0);

add_object_constant("__backend", default_backend_obj, 0);
add_program_constant("DefaultBackendClass", default_backend_obj->prog, 0);
}
}

#ifdef DO_PIKE_CLEANUP
void exit_backend(void)
{
/* Note: The mem_callback has already been freed
   *       by exit_builtin_efuns() at this point.
   */
/* if (mem_callback) remove_callback(mem_callback); */
free_object(default_backend_obj);
default_backend = 0;

#ifdef class_Backend_defined

#ifdef class_Backend_CallOut_defined
  if(Backend_CallOut_program) {
#line 474 "/Users/hww3/devel/pike/src/backend.cmod"
    free_program(Backend_CallOut_program);
    Backend_CallOut_program=0;
  }

#endif /* class_Backend_CallOut_defined */
  if(Backend_program) {
#line 275 "/Users/hww3/devel/pike/src/backend.cmod"
    free_program(Backend_program);
    Backend_program=0;
  }

#endif /* class_Backend_defined */

#ifdef class_PollDeviceBackend_defined
  if(PollDeviceBackend_program) {
#line 3267 "/Users/hww3/devel/pike/src/backend.cmod"
    free_program(PollDeviceBackend_program);
    PollDeviceBackend_program=0;
  }

#endif /* class_PollDeviceBackend_defined */

#ifdef class_PollBackend_defined
  if(PollBackend_program) {
#line 4547 "/Users/hww3/devel/pike/src/backend.cmod"
    free_program(PollBackend_program);
    PollBackend_program=0;
  }

#endif /* class_PollBackend_defined */

#ifdef class_SelectBackend_defined
  if(SelectBackend_program) {
#line 5157 "/Users/hww3/devel/pike/src/backend.cmod"
    free_program(SelectBackend_program);
    SelectBackend_program=0;
  }

#endif /* class_SelectBackend_defined */

#ifdef module_strings_declared
{
  int i;
  for(i=0; i < 1; i++) {
    if (module_strings[i]) free_string(module_strings[i]);
    module_strings[i] = NULL;
  }
}
#endif
#line 6146 "/Users/hww3/devel/pike/src/backend.cmod"
;
}

/* Note: This is called when the last backend object exits, which might be
 * after exit_backend if there's garbage. */
static void backend_cleanup(void)
{
#ifdef OPEN_POLL_DEVICE
 if (pdb_backends) {
free(pdb_backends);
num_pdb_backends = 0;
}
#endif /* OPEN_POLL_DEVICE */
 free_all_compat_cb_box_blocks();
if(fd_map)
{
free(fd_map);
fd_map=0;
fd_map_size=0;
}
#ifdef HAVE_BROKEN_F_SETFD
 cleanup_close_on_exec();
#endif /* HAVE_BROKEN_F_SETFD */
}
#endif


#ifdef CMOD_MAP_PROGRAM_IDS_DEFINED
static int ___cmod_map_program_ids(int id)
{
  int i = 0;
  if( (id&0x7f000000) != 0x7f000000 ) return id;
  id = id&0x00ffffff;
#ifdef class_PollDeviceBackend_defined
if(id==4) return PollDeviceBackend_program->id;
#endif
#ifdef class_PollBackend_defined
if(id==5) return PollBackend_program->id;
#endif
#ifdef class_SelectBackend_defined
if(id==6) return SelectBackend_program->id;
#endif
#ifdef class_Backend_defined
if(id==2) return Backend_program->id;
#endif
#ifdef class_Backend_CallOut_defined
if(id==3) return Backend_CallOut_program->id;
#endif
  while(___cmod_ext_used[i].from ) {
   if( ___cmod_ext_used[i].from == id ) return ___cmod_ext_used[i].to;
   i++;
  }
  return 0;
}
#endif /* CMOD_MAP_PROGRAM_IDS_DEFINED */
