LIBCOUCHBASE_API lcb_error_t lcb_create_libev_io_opts(int version, lcb_io_opt_t *io, void *arg) { struct ev_loop *loop = arg; struct lcb_io_opt_st *ret; struct libev_cookie *cookie; if (version != 0) { return LCB_PLUGIN_VERSION_MISMATCH; } ret = calloc(1, sizeof(*ret)); cookie = calloc(1, sizeof(*cookie)); if (ret == NULL || cookie == NULL) { free(ret); free(cookie); return LCB_CLIENT_ENOMEM; } /* setup io iops! */ ret->version = 0; ret->dlhandle = NULL; ret->destructor = lcb_destroy_io_opts; /* consider that struct isn't allocated by the library, * `need_cleanup' flag might be set in lcb_create() */ ret->v.v0.need_cleanup = 0; ret->v.v0.delete_event = lcb_io_delete_event; ret->v.v0.destroy_event = lcb_io_destroy_event; ret->v.v0.create_event = lcb_io_create_event; ret->v.v0.update_event = lcb_io_update_event; ret->v.v0.delete_timer = lcb_io_delete_timer; ret->v.v0.destroy_timer = lcb_io_destroy_timer; ret->v.v0.create_timer = lcb_io_create_event; ret->v.v0.update_timer = lcb_io_update_timer; ret->v.v0.run_event_loop = lcb_io_run_event_loop; ret->v.v0.stop_event_loop = lcb_io_stop_event_loop; wire_lcb_bsd_impl(ret); if (loop == NULL) { if ((cookie->loop = ev_loop_new(EVFLAG_AUTO | EVFLAG_NOENV)) == NULL) { free(ret); free(cookie); return LCB_CLIENT_ENOMEM; } cookie->allocated = 1; } else { cookie->loop = loop; cookie->allocated = 0; } cookie->suspended = 1; ret->v.v0.cookie = cookie; *io = ret; return LCB_SUCCESS; }
LIBCOUCHBASE_API lcb_error_t lcb_create_io_ops(lcb_io_opt_t *io, const struct lcb_create_io_ops_st *io_opts) { struct lcb_create_io_ops_st options; lcb_error_t err; plugin_info pi; memset(&options, 0, sizeof(options)); err = lcb_initialize_socket_subsystem(); if (err != LCB_SUCCESS) { return err; } err = generate_options(&pi, io_opts, &options, NULL); if (err != LCB_SUCCESS) { return err; } if (options.version == 1) { err = create_v1(io, &options); } else if (options.version == 2) { err = create_v2(io, &options); } else { return LCB_NOT_SUPPORTED; } if (err != LCB_SUCCESS) { return err; } /*XXX: * This block of code here because the Ruby SDK relies on undocumented * functionality of older versions of libcouchbase in which its send/recv * functions assert that the number of IOV elements passed is always going * to be 2. * * This works around the issue by patching the send/recv functions of * the ruby implementation at load-time. * * This block of code will go away once the Ruby SDK is fixed and a released * version has been out for enough time that it won't break common existing * deployments. */ if (io_opts && io_opts->version == 1 && io_opts->v.v1.symbol != NULL) { if (strstr(io_opts->v.v1.symbol, "cb_create_ruby")) { wire_lcb_bsd_impl(*io); } } return LCB_SUCCESS; }
LIBCOUCHBASE_API lcb_error_t lcb_create_libevent_io_opts(int version, lcb_io_opt_t *io, void *arg) { struct event_base *base = arg; struct lcb_io_opt_st *ret; struct libevent_cookie *cookie; if (version != 0) { return LCB_PLUGIN_VERSION_MISMATCH; } ret = calloc(1, sizeof(*ret)); cookie = calloc(1, sizeof(*cookie)); if (ret == NULL || cookie == NULL) { free(ret); free(cookie); return LCB_CLIENT_ENOMEM; } /* setup io iops! */ ret->version = 3; ret->dlhandle = NULL; ret->destructor = lcb_destroy_io_opts; /* consider that struct isn't allocated by the library, * `need_cleanup' flag might be set in lcb_create() */ ret->v.v3.need_cleanup = 0; if (base == NULL) { if ((cookie->base = event_base_new()) == NULL) { free(ret); free(cookie); return LCB_CLIENT_ENOMEM; } cookie->allocated = 1; } else { cookie->base = base; cookie->allocated = 0; } ret->v.v3.cookie = cookie; ret->v.v3.get_procs = procs2_lnt_callback; /* For back-compat */ wire_lcb_bsd_impl(ret); *io = ret; return LCB_SUCCESS; }
SV * PLCB_ioprocs_new(SV *options) { plcb_IOPROCS async_s = { NULL }, *async = NULL; lcb_io_opt_t cbcio = NULL; SV *ptriv, *blessedrv; /* First make sure all the options are ok */ plcb_OPTION argopts[] = { #define X(name, t, tgt) PLCB_KWARG(name, t, &async_s.tgt), X_IOPROCS_OPTIONS(X) #undef X { NULL } }; plcb_extract_args(options, argopts); /* Verify we have at least the basic functions */ if (!async_s.cv_evmod) { die("Need event_update"); } if (!async_s.cv_timermod) { die("Need timer_update"); } if (!async_s.userdata) { async_s.userdata = &PL_sv_undef; } Newxz(cbcio, 1, struct lcb_io_opt_st); Newxz(async, 1, plcb_IOPROCS); *async = async_s; #define X(name, t, tgt) SvREFCNT_inc(async->tgt); X_IOPROCS_OPTIONS(X) #undef X ptriv = newSViv(PTR2IV(async)); blessedrv = newRV_noinc(ptriv); sv_bless(blessedrv, gv_stashpv(PLCB_IOPROCS_CLASS, GV_ADD)); async->refcount = 1; async->iops_ptr = cbcio; cbcio->v.v0.cookie = async; async->selfrv = newRV_inc(ptriv); sv_rvweaken(async->selfrv); async->action_sv = newSViv(0); SvREADONLY_on(async->action_sv); async->flags_sv = newSViv(0); SvREADONLY_on(async->flags_sv); async->usec_sv = newSVnv(0); SvREADONLY_on(async->usec_sv); async->sched_r_sv = newSViv(0); SvREADONLY_on(async->sched_r_sv); async->sched_w_sv = newSViv(0); SvREADONLY_on(async->sched_w_sv); async->stop_r_sv = newSViv(0); SvREADONLY_on(async->stop_r_sv); async->stop_w_sv = newSViv(0); SvREADONLY_on(async->stop_w_sv); /* i/o events */ cbcio->v.v0.create_event = create_event; cbcio->v.v0.destroy_event = destroy_event; cbcio->v.v0.update_event = update_event; cbcio->v.v0.delete_event = delete_event; /* timer events */ cbcio->v.v0.create_timer = create_timer; cbcio->v.v0.destroy_timer = destroy_event; cbcio->v.v0.delete_timer = delete_timer; cbcio->v.v0.update_timer = update_timer; wire_lcb_bsd_impl(cbcio); cbcio->v.v0.run_event_loop = startstop_dummy; cbcio->v.v0.stop_event_loop = startstop_dummy; cbcio->v.v0.need_cleanup = 0; /* Now all we need to do is return the blessed reference */ return blessedrv; }