int adaptor_init(zhandle_t *zh) { pthread_mutexattr_t recursive_mx_attr; struct adaptor_threads *adaptor_threads = calloc(1, sizeof(*adaptor_threads)); if (!adaptor_threads) { LOG_ERROR(("Out of memory")); return -1; } /* We use a pipe for interrupting select() in unix/sol and socketpair in windows. */ #ifdef WIN32 if (create_socket_pair(adaptor_threads->self_pipe) == -1){ LOG_ERROR(("Can't make a socket.")); #else if(pipe(adaptor_threads->self_pipe)==-1) { LOG_ERROR(("Can't make a pipe %d",errno)); #endif free(adaptor_threads); return -1; } set_nonblock(adaptor_threads->self_pipe[1]); set_nonblock(adaptor_threads->self_pipe[0]); pthread_mutex_init(&zh->auth_h.lock,0); zh->adaptor_priv = adaptor_threads; pthread_mutex_init(&zh->to_process.lock,0); pthread_mutex_init(&adaptor_threads->zh_lock,0); pthread_mutex_init(&adaptor_threads->reconfig_lock,0); // to_send must be recursive mutex pthread_mutexattr_init(&recursive_mx_attr); pthread_mutexattr_settype(&recursive_mx_attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&zh->to_send.lock,&recursive_mx_attr); pthread_mutexattr_destroy(&recursive_mx_attr); pthread_mutex_init(&zh->sent_requests.lock,0); pthread_cond_init(&zh->sent_requests.cond,0); pthread_mutex_init(&zh->completions_to_process.lock,0); pthread_cond_init(&zh->completions_to_process.cond,0); start_threads(zh); return 0; } void adaptor_finish(zhandle_t *zh) { struct adaptor_threads *adaptor_threads; // make sure zh doesn't get destroyed until after we're done here api_prolog(zh); adaptor_threads = zh->adaptor_priv; if(adaptor_threads==0) { api_epilog(zh,0); return; } if(!pthread_equal(adaptor_threads->io,pthread_self())){ wakeup_io_thread(zh); pthread_join(adaptor_threads->io, 0); }else pthread_detach(adaptor_threads->io); if(!pthread_equal(adaptor_threads->completion,pthread_self())){ pthread_mutex_lock(&zh->completions_to_process.lock); pthread_cond_broadcast(&zh->completions_to_process.cond); pthread_mutex_unlock(&zh->completions_to_process.lock); pthread_join(adaptor_threads->completion, 0); }else pthread_detach(adaptor_threads->completion); api_epilog(zh,0); } void adaptor_destroy(zhandle_t *zh) { struct adaptor_threads *adaptor = zh->adaptor_priv; if(adaptor==0) return; pthread_cond_destroy(&adaptor->cond); pthread_mutex_destroy(&adaptor->lock); pthread_mutex_destroy(&zh->to_process.lock); pthread_mutex_destroy(&zh->to_send.lock); pthread_mutex_destroy(&zh->sent_requests.lock); pthread_cond_destroy(&zh->sent_requests.cond); pthread_mutex_destroy(&zh->completions_to_process.lock); pthread_cond_destroy(&zh->completions_to_process.cond); pthread_mutex_destroy(&adaptor->zh_lock); pthread_mutex_destroy(&zh->auth_h.lock); close(adaptor->self_pipe[0]); close(adaptor->self_pipe[1]); free(adaptor); zh->adaptor_priv=0; } int wakeup_io_thread(zhandle_t *zh) { struct adaptor_threads *adaptor_threads = zh->adaptor_priv; char c=0; #ifndef WIN32 return write(adaptor_threads->self_pipe[1],&c,1)==1? ZOK: ZSYSTEMERROR; #else return send(adaptor_threads->self_pipe[1], &c, 1, 0)==1? ZOK: ZSYSTEMERROR; #endif } int adaptor_send_queue(zhandle_t *zh, int timeout) { if(!zh->close_requested) return wakeup_io_thread(zh); // don't rely on the IO thread to send the messages if the app has // requested to close return flush_send_queue(zh, timeout); } /* These two are declared here because we will run the event loop * and not the client */ #ifdef WIN32 int zookeeper_interest(zhandle_t *zh, SOCKET *fd, int *interest, struct timeval *tv); #else int zookeeper_interest(zhandle_t *zh, int *fd, int *interest, struct timeval *tv); #endif int zookeeper_process(zhandle_t *zh, int events); #ifdef WIN32 unsigned __stdcall do_io( void * v) #else void *do_io(void *v) #endif { zhandle_t *zh = (zhandle_t*)v; #ifndef WIN32 struct pollfd fds[2]; struct adaptor_threads *adaptor_threads = zh->adaptor_priv; api_prolog(zh); notify_thread_ready(zh); LOG_DEBUG(("started IO thread")); fds[0].fd=adaptor_threads->self_pipe[0]; fds[0].events=POLLIN; while(!zh->close_requested) { struct timeval tv; int fd; int interest; int timeout; int maxfd=1; int rc; zookeeper_interest(zh, &fd, &interest, &tv); if (fd != -1) { fds[1].fd=fd; fds[1].events=(interest&ZOOKEEPER_READ)?POLLIN:0; fds[1].events|=(interest&ZOOKEEPER_WRITE)?POLLOUT:0; maxfd=2; } timeout=tv.tv_sec * 1000 + (tv.tv_usec/1000); poll(fds,maxfd,timeout); if (fd != -1) { interest=(fds[1].revents&POLLIN)?ZOOKEEPER_READ:0; interest|=((fds[1].revents&POLLOUT)||(fds[1].revents&POLLHUP))?ZOOKEEPER_WRITE:0; } if(fds[0].revents&POLLIN){ // flush the pipe char b[128]; while(read(adaptor_threads->self_pipe[0],b,sizeof(b))==sizeof(b)){} } #else fd_set rfds, wfds, efds; struct adaptor_threads *adaptor_threads = zh->adaptor_priv; api_prolog(zh); notify_thread_ready(zh); LOG_DEBUG(("started IO thread")); FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); while(!zh->close_requested) { struct timeval tv; SOCKET fd; SOCKET maxfd=adaptor_threads->self_pipe[0]; int interest; int rc; zookeeper_interest(zh, &fd, &interest, &tv); if (fd != -1) { if (interest&ZOOKEEPER_READ) { FD_SET(fd, &rfds); } else { FD_CLR(fd, &rfds); } if (interest&ZOOKEEPER_WRITE) { FD_SET(fd, &wfds); } else { FD_CLR(fd, &wfds); } } FD_SET( adaptor_threads->self_pipe[0] ,&rfds ); rc = select((int)maxfd, &rfds, &wfds, &efds, &tv); if (fd != -1) { interest = (FD_ISSET(fd, &rfds))? ZOOKEEPER_READ:0; interest|= (FD_ISSET(fd, &wfds))? ZOOKEEPER_WRITE:0; } if (FD_ISSET(adaptor_threads->self_pipe[0], &rfds)){ // flush the pipe/socket char b[128]; while(recv(adaptor_threads->self_pipe[0],b,sizeof(b), 0)==sizeof(b)){} } #endif // dispatch zookeeper events rc = zookeeper_process(zh, interest); // check the current state of the zhandle and terminate // if it is_unrecoverable() if(is_unrecoverable(zh)) break; } api_epilog(zh, 0); LOG_DEBUG(("IO thread terminated")); return 0; } #ifdef WIN32 unsigned __stdcall do_completion( void * v) #else void *do_completion(void *v) #endif { zhandle_t *zh = v; api_prolog(zh); notify_thread_ready(zh); LOG_DEBUG(("started completion thread")); while(!zh->close_requested) { pthread_mutex_lock(&zh->completions_to_process.lock); while(!zh->completions_to_process.head && !zh->close_requested) { pthread_cond_wait(&zh->completions_to_process.cond, &zh->completions_to_process.lock); } pthread_mutex_unlock(&zh->completions_to_process.lock); process_completions(zh); } api_epilog(zh, 0); LOG_DEBUG(("completion thread terminated")); return 0; }
/** * @brief Reads a whole line from the input channel. * @note Input chars are echoed on the same stream object with the * following exceptions: * - DEL and BS are echoed as BS-SPACE-BS. * - CR is echoed as CR-LF. * - 0x4 is echoed as "^D". * - Other values below 0x20 are not echoed. * . * * @param[in] scfg pointer to a @p ShellConfig object * @param[in] line pointer to the line buffer * @param[in] size buffer maximum length * @param[in] shp pointer to a @p ShellHistory object or NULL * @return The operation status. * @retval true the channel was reset or CTRL-D pressed. * @retval false operation successful. * * @api */ bool shellGetLine(ShellConfig *scfg, char *line, unsigned size, ShellHistory *shp) { char *p = line; BaseSequentialStream *chp = scfg->sc_channel; #if SHELL_USE_ESC_SEQ == TRUE bool escape = false; bool bracket = false; #endif #if SHELL_USE_HISTORY != TRUE (void) shp; #endif while (true) { char c; if (streamRead(chp, (uint8_t *)&c, 1) == 0) return true; #if SHELL_USE_ESC_SEQ == TRUE if (c == 27) { escape = true; continue; } if (escape) { escape = false; if (c == '[') { escape = true; bracket = true; continue; } if (bracket) { bracket = false; #if SHELL_USE_HISTORY == TRUE if (c == 'A') { int len = get_history(shp, line, SHELL_HIST_DIR_BK); if (len > 0) { _shell_reset_cur(chp); _shell_clr_line(chp); chprintf(chp, "%s", line); p = line + len; } continue; } if (c == 'B') { int len = get_history(shp, line, SHELL_HIST_DIR_FW); if (len == 0) *line = 0; if (len >= 0) { _shell_reset_cur(chp); _shell_clr_line(chp); chprintf(chp, "%s", line); p = line + len; } continue; } #endif } continue; } #endif #if (SHELL_CMD_EXIT_ENABLED == TRUE) && !defined(_CHIBIOS_NIL_) if (c == 4) { chprintf(chp, "^D"); return true; } #endif if ((c == 8) || (c == 127)) { if (p != line) { streamPut(chp, 0x08); streamPut(chp, 0x20); streamPut(chp, 0x08); p--; } continue; } if (c == '\r') { chprintf(chp, SHELL_NEWLINE_STR); #if SHELL_USE_HISTORY == TRUE save_history(shp, line, p - line); #endif *p = 0; return false; } #if SHELL_USE_COMPLETION == TRUE if (c == '\t') { if (p < line + size - 1) { *p = 0; get_completions(scfg, line); int len = process_completions(scfg, line, p - line, size); if (len > 0) { write_completions(scfg, line, p - line); p = line + len; } } continue; } #endif #if SHELL_USE_HISTORY == TRUE if (c == 14) { int len = get_history(shp, line, SHELL_HIST_DIR_FW); if (len == 0) *line = 0; if (len >= 0) { _shell_reset_cur(chp); _shell_clr_line(chp); chprintf(chp, "%s", line); p = line + len; } continue; } if (c == 16) { int len = get_history(shp, line, SHELL_HIST_DIR_BK); if (len > 0) { _shell_reset_cur(chp); _shell_clr_line(chp); chprintf(chp, "%s", line); p = line + len; } continue; } #endif if (c < 0x20) continue; if (p < line + size - 1) { streamPut(chp, c); *p++ = (char)c; } } }