static void do_start(void* arg) { PortState* state = (PortState*)arg; erl_drv_mutex_lock(G_ENGINE_STATE_LOCK); if (G_ENGINE_STATE == ENGINE_STOPPED) { // Engine was stopped; set the flag, unlock and run the start G_ENGINE_STATE = ENGINE_STARTING; erl_drv_mutex_unlock(G_ENGINE_STATE_LOCK); // Run the startup without holding any lock -- this can take a while // if we are recovering from previous errors ib_err_t error = ib_startup("barracuda"); if (error == DB_SUCCESS) { // Make sure the innokeystore database exists // TODO: Avoid hard-coding the db name here... if (ib_database_create("innokeystore") != IB_TRUE) { error = DB_ERROR; } } // Relock and sort out results erl_drv_mutex_lock(G_ENGINE_STATE_LOCK); if (error == DB_SUCCESS) { G_ENGINE_STATE = ENGINE_STARTED; send_ok(state); } else { G_ENGINE_STATE = ENGINE_STOPPED; send_error_str(state, ib_strerror(error)); } } else if (G_ENGINE_STATE == ENGINE_STARTED) { // another thread has already completed startup send_ok(state); } else { // Engine was not in stopped state when do_start was called. // Probably due to multiple threads trying to start at the // same time. assert(G_ENGINE_STATE == ENGINE_STARTING); send_error_atom(state, "starting"); } erl_drv_mutex_unlock(G_ENGINE_STATE_LOCK); }
static void innostore_drv_stop(ErlDrvData handle) { PortState* state = (PortState*)handle; // Grab the worker lock, in case we have an job running erl_drv_mutex_lock(state->worker_lock); // Signal the shutdown and wait until the current operation has completed state->shutdown_flag = 1; erl_drv_cond_signal(state->worker_cv); while (state->op) { erl_drv_cond_wait(state->worker_cv, state->worker_lock); } // If the port state is not marked as READY, close the cursor and abort the txn if (state->port_state != STATE_READY) { ib_cursor_close(state->cursor); ib_trx_rollback(state->txn); } // No pending jobs and we have the lock again -- join our worker thread erl_drv_cond_signal(state->worker_cv); erl_drv_mutex_unlock(state->worker_lock); erl_drv_thread_join(state->worker, 0); // Cleanup erl_drv_cond_destroy(state->worker_cv); erl_drv_mutex_destroy(state->worker_lock); driver_free(handle); }
int start_native_gui(wxe_data *sd) { int res; wxe_status_m = erl_drv_mutex_create((char *) "wxe_status_m"); wxe_status_c = erl_drv_cond_create((char *)"wxe_status_c"); wxe_batch_locker_m = erl_drv_mutex_create((char *)"wxe_batch_locker_m"); wxe_batch_locker_c = erl_drv_cond_create((char *)"wxe_batch_locker_c"); init_caller = driver_connected(sd->port_handle); #ifdef __DARWIN__ res = erl_drv_steal_main_thread((char *)"wxwidgets", &wxe_thread,wxe_main_loop,(void *) sd->pdl,NULL); #else ErlDrvThreadOpts *opts = erl_drv_thread_opts_create((char *)"wx thread"); opts->suggested_stack_size = 8192; res = erl_drv_thread_create((char *)"wxwidgets", &wxe_thread,wxe_main_loop,(void *) sd->pdl,opts); erl_drv_thread_opts_destroy(opts); #endif if(res == 0) { erl_drv_mutex_lock(wxe_status_m); for(;wxe_status == WXE_NOT_INITIATED;) { erl_drv_cond_wait(wxe_status_c, wxe_status_m); } erl_drv_mutex_unlock(wxe_status_m); return wxe_status; } else { wxString msg; msg.Printf(wxT("Erlang failed to create wxe-thread %d\r\n"), res); send_msg("error", &msg); return -1; } }
void WxeApp::dispatch_cmds() { erl_drv_mutex_lock(wxe_batch_locker_m); int level = dispatch(wxe_batch_cb_saved, 0, WXE_STORED); dispatch(wxe_batch, level, WXE_NORMAL); wxe_batch_caller = 0; erl_drv_mutex_unlock(wxe_batch_locker_m); }
// Should have erl_drv_mutex_lock(wxe_batch_locker_m); // when entering this function and it should be released // afterwards int WxeApp::dispatch(wxList * batch, int blevel, int list_type) { int ping = 0; // erl_drv_mutex_lock(wxe_batch_locker_m); must be locked already while(true) { if (batch->size() > 0) { for( wxList::compatibility_iterator node = batch->GetFirst(); node; node = batch->GetFirst()) { wxeCommand *event = (wxeCommand *)node->GetData(); batch->Erase(node); switch(event->op) { case WXE_BATCH_END: {--blevel; } break; case WXE_BATCH_BEGIN: {blevel++; } break; case WXE_DEBUG_PING: // When in debugger we don't want to hang waiting for a BATCH_END // that never comes, because a breakpoint have hit. ping++; if(ping > 2) blevel = 0; break; case WXE_CB_RETURN: // erl_drv_mutex_unlock(wxe_batch_locker_m); should be called after // whatever cleaning is necessary memcpy(cb_buff, event->buffer, event->len); return blevel; default: erl_drv_mutex_unlock(wxe_batch_locker_m); if(event->op < OPENGL_START) { // fprintf(stderr, " c %d (%d) \r\n", event->op, blevel); wxe_dispatch(*event); } else { gl_dispatch(event->op,event->buffer,event->caller,event->bin); } erl_drv_mutex_lock(wxe_batch_locker_m); break; } delete event; } } else { if((list_type == WXE_STORED) || (blevel <= 0 && list_type == WXE_NORMAL)) { // erl_drv_mutex_unlock(wxe_batch_locker_m); should be called after // whatever cleaning is necessary return blevel; } // sleep until something happens //fprintf(stderr, "%s:%d sleep %d %d %d %d \r\n", __FILE__, __LINE__, batch->size(), callback_returned, blevel, is_callback);fflush(stderr); wxe_batch_caller++; while(batch->size() == 0) { erl_drv_cond_wait(wxe_batch_locker_c, wxe_batch_locker_m); } } } }
// Init wx-widgets thread bool WxeApp::OnInit() { /* Create a dummy window so wxWidgets don't automagicly quits the main loop after the last window */ global_me = new wxeMemEnv(); wxe_batch = new wxList; wxe_batch_cb_saved = new wxList; create_dummy_window(); wxe_ps_init(); wxIdleEvent::SetMode(wxIDLE_PROCESS_SPECIFIED); this->Connect(wxID_ANY, wxEVT_IDLE, (wxObjectEventFunction) (wxEventFunction) &WxeApp::idle); this->Connect(CREATE_PORT, wxeEVT_META_COMMAND, (wxObjectEventFunction) (wxEventFunction) &WxeApp::newMemEnv); this->Connect(DELETE_PORT, wxeEVT_META_COMMAND, (wxObjectEventFunction) (wxEventFunction) &WxeApp::destroyMemEnv); this->Connect(WXE_SHUTDOWN, wxeEVT_META_COMMAND, (wxObjectEventFunction) (wxEventFunction) &WxeApp::shutdown); // fprintf(stderr, "Size void* %d: long %d long long %d int64 %d \r\n", // sizeof(void *), sizeof(long), sizeof(long long), sizeof(wxInt64)); initEventTable(); wxInitAllImageHandlers(); init_nonconsts(global_me, init_caller); erl_drv_mutex_lock(wxe_status_m); wxe_status = WXE_INITIATED; gl_initiated = FALSE; erl_drv_cond_signal(wxe_status_c); erl_drv_mutex_unlock(wxe_status_m); return TRUE; }
void WxeApp::dispatch_cb(wxList * batch, wxList * temp, ErlDrvTermData process) { int callback_returned = 0; while(true) { if (batch->size() > 0) { for( wxList::compatibility_iterator node = batch->GetFirst(); node; node = batch->GetFirst()) { wxeCommand *event = (wxeCommand *)node->GetData(); wxeMemEnv *memenv = getMemEnv(event->port); batch->Erase(node); if(event->caller == process || // Callbacks from CB process only event->op == WXE_CB_START || // Recursive event callback allow // Allow connect_cb during CB i.e. msg from wxe_server. (memenv && event->caller == memenv->owner)) { switch(event->op) { case WXE_BATCH_END: case WXE_BATCH_BEGIN: case WXE_DEBUG_PING: break; case WXE_CB_RETURN: memcpy(cb_buff, event->buffer, event->len); callback_returned = 1; return; case WXE_CB_START: // CB start from now accept message from CB process only process = event->caller; break; default: erl_drv_mutex_unlock(wxe_batch_locker_m); if(event->op < OPENGL_START) { // fprintf(stderr, " cb %d \r\n", event->op); wxe_dispatch(*event); } else { gl_dispatch(event->op,event->buffer,event->caller,event->bin); } erl_drv_mutex_lock(wxe_batch_locker_m); break; if(callback_returned) return; } delete event; } else { // fprintf(stderr, " sav %d \r\n", event->op); temp->Append(event); } } } else { if(callback_returned) { return; } // sleep until something happens //fprintf(stderr, "%s:%d sleep %d %d %d %d \r\n", __FILE__, __LINE__, batch->size(), callback_returned, blevel, is_callback);fflush(stderr); while(batch->size() == 0) { erl_drv_cond_wait(wxe_batch_locker_c, wxe_batch_locker_m); } } } }
int start_native_gui(wxe_data *sd) { int res; wxe_status_m = erl_drv_mutex_create((char *) "wxe_status_m"); wxe_status_c = erl_drv_cond_create((char *)"wxe_status_c"); wxe_batch_locker_m = erl_drv_mutex_create((char *)"wxe_batch_locker_m"); wxe_batch_locker_c = erl_drv_cond_create((char *)"wxe_batch_locker_c"); init_caller = driver_connected(sd->port); if((res = erl_drv_thread_create((char *)"wxwidgets", &wxe_thread,wxe_main_loop,(void *) sd->pdl,NULL)) == 0) { erl_drv_mutex_lock(wxe_status_m); for(;wxe_status == WXE_NOT_INITIATED;) { erl_drv_cond_wait(wxe_status_c, wxe_status_m); } erl_drv_mutex_unlock(wxe_status_m); return wxe_status; } else { wxString msg; msg.Printf(wxT("Erlang failed to create wxe-thread %d\r\n"), res); send_msg("error", &msg); return -1; } }
void mutex_unlock(mutex_t* mutex){ #ifdef USE_PTHREAD pthread_mutex_unlock(mutex); #elif defined USE_ETHREAD erl_drv_mutex_unlock(*mutex); #endif }
void *wxe_main_loop(void *vpdl) { int result; int argc = 1; char * temp = (char *) "Erlang\0"; char ** argv = &temp; ErlDrvPDL pdl = (ErlDrvPDL) vpdl; driver_pdl_inc_refc(pdl); // ErlDrvSysInfo einfo; // driver_system_info(&einfo, sizeof(ErlDrvSysInfo)); // Disable floating point execption if they are on. // This should be done in emulator but it's not in yet. #ifndef _WIN32 erts_thread_disable_fpe(); #endif result = wxEntry(argc, argv); // fprintf(stderr, "WXWidgets quits main loop %d \r\n", result); if(result >= 0 && wxe_status == WXE_INITIATED) { /* We are done try to make a clean exit */ wxe_status = WXE_EXITED; driver_pdl_dec_refc(pdl); erl_drv_thread_exit(NULL); return NULL; } else { erl_drv_mutex_lock(wxe_status_m); wxe_status = WXE_ERROR; erl_drv_cond_signal(wxe_status_c); erl_drv_mutex_unlock(wxe_status_m); driver_pdl_dec_refc(pdl); return NULL; } }
void push_command(int op,char * buf,int len, wxe_data *sd) { /* fprintf(stderr, "Op %d %d [%ld] %d\r\n", op, (int) driver_caller(sd->port_handle), wxe_batch->size(), wxe_batch_caller),fflush(stderr); */ erl_drv_mutex_lock(wxe_batch_locker_m); wxe_queue->Add(op, buf, len, sd); if(wxe_needs_signal) { // wx-thread is waiting on batch end in cond_wait erl_drv_cond_signal(wxe_batch_locker_c); erl_drv_mutex_unlock(wxe_batch_locker_m); } else { // wx-thread is waiting gui-events erl_drv_mutex_unlock(wxe_batch_locker_m); wxWakeUpIdle(); } }
void handle_callback_batch(ErlDrvPort port) { WxeApp * app = (WxeApp *) wxTheApp; // Should we be able to handle commands when recursing? probably erl_drv_mutex_lock(wxe_batch_locker_m); app->dispatch(wxe_batch, 0, WXE_CALLBACK); wxe_batch_caller = 0; erl_drv_mutex_unlock(wxe_batch_locker_m); }
static void syslogdrv_stop(ErlDrvData handle) { syslogdrv_t* d = (syslogdrv_t*)handle; erl_drv_mutex_lock(syslog_mtx); closelog(); erl_drv_mutex_unlock(syslog_mtx); if (d->ident) { driver_free(d->ident); } driver_free((char*)handle); }
static void enqueue_reply(Otp9302AsyncData *adata) { Otp9302MsgQ *msgq = adata->msgq; adata->next = NULL; adata->refc++; erl_drv_mutex_lock(msgq->mtx); if (msgq->end) msgq->end->next = adata; else msgq->end = msgq->start = adata; msgq->end = adata; erl_drv_mutex_unlock(msgq->mtx); }
void handle_event_callback(ErlDrvPort port, ErlDrvTermData process) { WxeApp * app = (WxeApp *) wxTheApp; ErlDrvMonitor monitor; driver_monitor_process(port, process, &monitor); // Should we be able to handle commands when recursing? probably erl_drv_mutex_lock(wxe_batch_locker_m); //fprintf(stderr, "\r\nCB Start ");fflush(stderr); app->dispatch_cb(wxe_batch, wxe_batch_cb_saved, process); //fprintf(stderr, ".. done \r\n");fflush(stderr); wxe_batch_caller = 0; erl_drv_mutex_unlock(wxe_batch_locker_m); driver_demonitor_process(port, &monitor); }
static void dequeue_replies(Otp9302AsyncData *adata) { Otp9302MsgQ *msgq = adata->msgq; erl_drv_mutex_lock(msgq->mtx); if (--adata->refc == 0) driver_free(adata); while (msgq->start) { send_reply(msgq->start); adata = msgq->start; msgq->start = msgq->start->next; if (--adata->refc == 0) driver_free(adata); } msgq->start = msgq->end = NULL; erl_drv_mutex_unlock(msgq->mtx); }
void meta_command(int what, wxe_data *sd) { if(what == PING_PORT) { erl_drv_mutex_lock(wxe_batch_locker_m); if(wxe_batch_caller > 0) { wxeCommand *Cmd = new wxeCommand(WXE_DEBUG_PING, NULL, 0, sd); wxe_batch->Append(Cmd); erl_drv_cond_signal(wxe_batch_locker_c); } wxWakeUpIdle(); erl_drv_mutex_unlock(wxe_batch_locker_m); } else { if(sd) { wxeMetaCommand Cmd(sd, what); wxTheApp->AddPendingEvent(Cmd); } } }
static void syslogdrv_output(ErlDrvData handle, char *buf, ErlDrvSizeT len) { syslogdrv_t* d = (syslogdrv_t*)handle; /* Incoming data is expected to start with an integer priority encoded as a 4-byte integer in network order, therefore make sure there's at least 5 bytes in the message. */ if (d->open && len > 4) { int priority = ntohl(*(uint32_t*)buf); buf += 4; /* re-call openlog in case another instance of the port driver * was called in the mean time */ erl_drv_mutex_lock(syslog_mtx); openlog(d->ident, d->logopt, d->facility); syslog(priority, "%s", buf); erl_drv_mutex_unlock(syslog_mtx); } }
dmessage_t* dthread_recv(dthread_t* thr, dthread_t** source) { dmessage_t* mp; erl_drv_mutex_lock(thr->iq_mtx); if ((mp = thr->iq_front) != NULL) { if (!(thr->iq_front = mp->next)) thr->iq_rear = NULL; thr->iq_len--; if (thr->iq_len == 0) dthread_signal_reset(thr); } erl_drv_mutex_unlock(thr->iq_mtx); if (mp && source) *source = mp->source; return mp; }
bool WxeApp::OnInit() { global_me = new wxeMemEnv(); wxe_queue = new wxeFifo(1000); wxe_queue_cb_saved = new wxeFifo(200); cb_buff = NULL; recurse_level = 0; delayed_delete = new wxeFifo(10); delayed_cleanup = new wxList; wxe_ps_init2(); // wxIdleEvent::SetMode(wxIDLE_PROCESS_SPECIFIED); // Hmm printpreview doesn't work in 2.9 with this Connect(wxID_ANY, wxEVT_IDLE, (wxObjectEventFunction) (wxEventFunction) &WxeApp::idle); Connect(CREATE_PORT, wxeEVT_META_COMMAND,(wxObjectEventFunction) (wxEventFunction) &WxeApp::newMemEnv); Connect(DELETE_PORT, wxeEVT_META_COMMAND,(wxObjectEventFunction) (wxEventFunction) &WxeApp::destroyMemEnv); Connect(WXE_SHUTDOWN, wxeEVT_META_COMMAND,(wxObjectEventFunction) (wxEventFunction) &WxeApp::shutdown); // fprintf(stderr, "Size void* %d: long %d long long %d int64 %d \r\n", // sizeof(void *), sizeof(long), sizeof(long long), sizeof(wxInt64)); initEventTable(); wxInitAllImageHandlers(); #ifdef _MACOSX /* Create a default MenuBar so that we can intercept the quit command */ wxMenuBar *macMB = new wxMenuBar; wxMenuBar::MacSetCommonMenuBar(macMB); macMB->MacInstallMenuBar(); macMB->Connect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction) (wxEventFunction) &WxeApp::dummy_close); #endif SetExitOnFrameDelete(false); init_nonconsts(global_me, init_caller); erl_drv_mutex_lock(wxe_status_m); wxe_status = WXE_INITIATED; erl_drv_cond_signal(wxe_status_c); erl_drv_mutex_unlock(wxe_status_m); return TRUE; }
void meta_command(int what, wxe_data *sd) { if(what == PING_PORT && wxe_status == WXE_INITIATED) { erl_drv_mutex_lock(wxe_batch_locker_m); if(wxe_needs_signal) { wxe_queue->Add(WXE_DEBUG_PING, NULL, 0, sd); erl_drv_cond_signal(wxe_batch_locker_c); } wxWakeUpIdle(); erl_drv_mutex_unlock(wxe_batch_locker_m); } else { if(sd && wxe_status == WXE_INITIATED) { wxeMetaCommand Cmd(sd, what); wxTheApp->AddPendingEvent(Cmd); if(what == DELETE_PORT) { driver_free(sd->bin); free(sd); } } } }
void push_command(int op,char * buf,int len, wxe_data *sd) { // fprintf(stderr, "Op %d %d\r\n", op, (int) driver_caller(sd->port)),fflush(stderr); wxeCommand *Cmd = new wxeCommand(op, buf, len, sd); erl_drv_mutex_lock(wxe_batch_locker_m); wxe_batch->Append(Cmd); if(wxe_batch_caller > 0) { // wx-thread is waiting on batch end in cond_wait erl_drv_cond_signal(wxe_batch_locker_c); } else { // wx-thread is waiting gui-events if(op == WXE_BATCH_BEGIN) { wxe_batch_caller = 1; } erl_drv_cond_signal(wxe_batch_locker_c); wxWakeUpIdle(); } erl_drv_mutex_unlock(wxe_batch_locker_m); }
void *wxe_main_loop(void *vpdl) { int result; int argc = 1; char * temp = (char *) "Erlang"; char * argv[] = {temp,NULL}; ErlDrvPDL pdl = (ErlDrvPDL) vpdl; driver_pdl_inc_refc(pdl); // Disable floating point execption if they are on. // This should be done in emulator but it's not in yet. #ifndef _WIN32 erts_thread_disable_fpe(); #else // Setup that wxWidgets should look for cursors and icons in // this dll and not in werl.exe (which is the default) HMODULE WXEHandle = GetModuleHandle(_T("wxe_driver")); wxSetInstance((HINSTANCE) WXEHandle); #endif wxe_ps_init(); result = wxEntry(argc, argv); // fprintf(stderr, "WXWidgets quits main loop %d \r\n", result); if(result >= 0 && wxe_status == WXE_INITIATED) { /* We are done try to make a clean exit */ wxe_status = WXE_EXITED; driver_pdl_dec_refc(pdl); #ifndef __DARWIN__ erl_drv_thread_exit(NULL); #endif return NULL; } else { erl_drv_mutex_lock(wxe_status_m); wxe_status = WXE_ERROR; erl_drv_cond_signal(wxe_status_c); erl_drv_mutex_unlock(wxe_status_m); driver_pdl_dec_refc(pdl); return NULL; } }
int dthread_send(dthread_t* thr, dthread_t* source, dmessage_t* mp) { dmessage_t* mr; int len; int r = 0; erl_drv_mutex_lock(thr->iq_mtx); mp->next = NULL; mp->source = source; if ((mr = thr->iq_rear) != NULL) mr->next = mp; else thr->iq_front = mp; thr->iq_rear = mp; len = ++thr->iq_len; if (len == 1) r = dthread_signal_set(thr); erl_drv_mutex_unlock(thr->iq_mtx); DEBUGF("dthread_send: iq_len=%d", len); return r; }
static void* innostore_worker(void* arg) { PortState* state = (PortState*)arg; erl_drv_mutex_lock(state->worker_lock); while (1) { // // NOTE: Holds the worker lock for the duration of the loop !! // if (state->shutdown_flag) { driver_free(state->work_buffer); state->work_buffer = 0; if (state->op != 0) { send_error_atom(state, "stopping"); state->op = 0; } erl_drv_cond_signal(state->worker_cv); erl_drv_mutex_unlock(state->worker_lock); break; } if (state->op) { state->op(state); state->op = 0; driver_free(state->work_buffer); state->work_buffer = 0; } else { erl_drv_cond_wait(state->worker_cv, state->worker_lock); } } return 0; }
int erts_mutex_unlock(erl_mutex_t mtx) { erl_drv_mutex_unlock((ErlDrvMutex *) mtx); return 0; }
void enif_mutex_unlock(ErlNifMutex *mtx) { erl_drv_mutex_unlock(mtx); }
int dthread_poll(dthread_t* thr, dthread_poll_event_t* events, size_t* nevents, int timeout) { struct timeval tm; struct timeval* tp; fd_set readfds; fd_set writefds; fd_set errorfds; int fd,nfds = 0; int ready; int i,n,iq_len=0; if (timeout < 0) tp = NULL; else { tm.tv_sec = timeout / 1000; tm.tv_usec = (timeout - tm.tv_sec*1000) * 1000; tp = &tm; } FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&errorfds); if ((fd = DTHREAD_EVENT(thr->iq_signal[0])) >= 0) { FD_SET(fd, &readfds); FD_SET(fd, &errorfds); DEBUGF("FD_SET: iq_signal[0] = %d", fd); if (fd > nfds) nfds = fd; } if (events && nevents && *nevents) { n = (int) (*nevents); for (i = 0; i < n; i++) { events[i].revents = 0; // clear here in case of timeout etc if (events[i].events) { fd = DTHREAD_EVENT(events[i].event); if (events[i].events & ERL_DRV_READ) { FD_SET(fd, &readfds); FD_SET(fd, &errorfds); } if (events[i].events & ERL_DRV_WRITE) FD_SET(fd, &writefds); if (fd > nfds) nfds = fd; } } } DEBUGF("select nfds=%d, tp=%p", nfds, tp); ready = select(nfds+1, &readfds, &writefds, &errorfds, tp); DEBUGF("select result r=%d", ready); if (ready <= 0) { if (nevents) *nevents = 0; return ready; } // check queue ! fd = DTHREAD_EVENT(thr->iq_signal[0]); if (FD_ISSET(fd, &readfds)) { erl_drv_mutex_lock(thr->iq_mtx); iq_len = thr->iq_len; erl_drv_mutex_unlock(thr->iq_mtx); ready--; } // check io events if (ready && events && nevents && *nevents) { size_t nready = 0; n = (int) (*nevents); for (i = 0; ready && (i < n); i++) { size_t fd_ready = 0; fd = DTHREAD_EVENT(events[i].event); if (FD_ISSET(fd, &readfds) || FD_ISSET(fd, &errorfds)) { events[i].revents |= ERL_DRV_READ; if (FD_ISSET(fd, &errorfds)) events[i].revents |= ERL_DRV_EXCEP; fd_ready = 1; } if (FD_ISSET(fd, &writefds)) { events[i].revents |= ERL_DRV_WRITE; fd_ready = 1; } nready += fd_ready; ready--; } *nevents = nready; } return iq_len; }
static void do_set_cfg(void* arg) { PortState* state = (PortState*)arg; erl_drv_mutex_lock(G_ENGINE_STATE_LOCK); if (G_ENGINE_STATE == ENGINE_STOPPED) { char* key = UNPACK_STRING(state->work_buffer, 0); const char* value = UNPACK_STRING(state->work_buffer, strlen(key)+1); if (strcmp(key, "error_log") == 0) { if (set_log_file(value) == 0) { send_ok(state); } else { send_error_atom(state, "einval"); } } else { // Check the expected type of the provided key so as to 1. validate it's a good key // and 2. know what setter to use. ib_cfg_type_t key_type; ib_err_t error = ib_cfg_var_get_type(key, &key_type); if (error == DB_SUCCESS) { if (key_type == IB_CFG_TEXT) { // HACK: Semantics of setting a text configuration value for innodb changed // to be pointer assignment (from copy) for vsn 1.0.6.6750. So, we strdup the // value to ensure everything works as expected. // TODO: Setup some sort of list of strdup'd values to ensure they all get // cleaned up properly. In typical usage, this isn't going to be a problem // as you only initialize once per run, but it bothers me just the same. error = ib_cfg_set(key, strdup(value)); } else { ErlDrvUInt value_i; UNPACK_INT(state->work_buffer, strlen(key)+1, &value_i); error = ib_cfg_set(key, value_i); } } if (error == DB_SUCCESS) { send_ok(state); } else { send_error_str(state, ib_strerror(error)); } } } else { send_error_atom(state, "starting"); } erl_drv_mutex_unlock(G_ENGINE_STATE_LOCK); }
static int innostore_drv_control(ErlDrvData handle, unsigned int cmd, char* inbuf, int inbuf_sz, char** outbuf, int outbuf_sz) { PortState* state = (PortState*)handle; // Grab the worker lock. erl_drv_mutex_lock(state->worker_lock); assert(state->op == 0); // Verify that caller is not attempting cursor operation when no cursor is // active (or vice-versa) if (state->port_state == STATE_READY && is_cmd(CMD_CURSOR_OPS)) { erl_drv_mutex_unlock(state->worker_lock); send_error_atom(state, "cursor_not_open"); return 0; } else if (state->port_state == STATE_CURSOR && !is_cmd(CMD_CURSOR_OPS)) { erl_drv_mutex_unlock(state->worker_lock); send_error_atom(state, "cursor_is_open"); return 0; } // Copy inbuf into our work buffer if (inbuf_sz > 0) { state->work_buffer = driver_alloc(inbuf_sz); memcpy(state->work_buffer, inbuf, inbuf_sz); } // Select the appropriate async op switch (cmd) { case CMD_SET_CFG: state->op = &do_set_cfg; break; case CMD_START: state->op = &do_start; break; case CMD_INIT_TABLE: state->op = &do_init_table; break; case CMD_IS_STARTED: // Check the global state -- prior to doing that, release our worker lock // so as to avoid weird locking overlaps. Store the true/false value as // a single byte in outbuf. No need to do any allocation as the VM always // provides a 64-byte outbuf buffer by default. assert(outbuf_sz > 0); erl_drv_mutex_unlock(state->worker_lock); erl_drv_mutex_lock(G_ENGINE_STATE_LOCK); (*outbuf)[0] = (G_ENGINE_STATE == ENGINE_STARTED); erl_drv_mutex_unlock(G_ENGINE_STATE_LOCK); return 1; case CMD_GET: state->op = &do_get; break; case CMD_PUT: state->op = &do_put; break; case CMD_DELETE: state->op = &do_delete; break; case CMD_LIST_TABLES: state->op = &do_list_tables; break; case CMD_CURSOR_OPEN: state->op = &do_cursor_open; break; case CMD_CURSOR_MOVE: state->op = &do_cursor_move; break; case CMD_CURSOR_CLOSE: state->op = &do_cursor_close; break; case CMD_DROP_TABLE: state->op = &do_drop_table; break; case CMD_STATUS: state->op = &do_status; break; } // Signal the worker erl_drv_cond_signal(state->worker_cv); erl_drv_mutex_unlock(state->worker_lock); *outbuf = 0; return 0; }