/* Destroys a ClientListener object and sets the pointer to NULL. */ void delClientListener(ClientListener** listener) { if(!listener || !*listener) return; /* Notify our threads that we are deleting the object. */ flag_raise(&(*listener)->flag_pole, OBJECT_DELETE_STATE); pthread_cond_broadcast(&(*listener)->t_cond); /* Delete dynamic members. */ delArrayList(&(*listener)->client_list); /* Close open file descriptors. */ if((*listener)->ep.efd) close((*listener)->ep.efd); /* Call destruction callbacks. */ if((*listener)->free_extended_data && (*listener)->ex_data) (*listener)->free_extended_data((*listener)->ex_data); pthread_mutex_destroy(&(*listener)->mutex); pthread_cond_destroy(&(*listener)->t_cond); free(*listener); *listener = NULL; }
/* Calls for the process waiter to stop, but it will * continue to run until at least one process exits. */ void proc_waiter_stop() { if(!proc_waiter_is_initialized()) return; /* Raise the flag to stop the thread, this should stop * the thread whenever a child process closes. */ flag_raise(&PROC_WAITER_FLAG_POLE, THREAD_STOP); /* Wake up the thread if it is waiting for a condition change. */ pthread_cond_broadcast(PROC_WAITER_T_COND); }
/* Similar to 'TcpClient_read_stop()', however it will not * block, but simply raise a flag for the reading thread to stop. * * This is good in many cases, however it is not as safe as the * synchronous version whenever the reading thread will be restarted. * If the reading thread is restarted before the thread returns, it * is possible that the restart will fail without warning. * To ensure the thread has returned after requesting for it to stop * asynchronously, call 'TcpClient_read_thread_wait()'. */ void TcpClient_read_stop_async(TcpClient* client) { if(!client)return; flag_raise(&client->flag_pole, THREAD_STOP); if((client->flag_pole & THREAD_CREATED) && (client->flag_pole & THREAD_IS_RUNNING)) { pthread_detach(client->read_thread); flag_lower(&client->flag_pole, THREAD_CREATED); } }
/* Stops the reading process on the client. * This function call WILL BLOCK until the reading thread returns * which may be several seconds, depending on the timeout set for recv(). * * If immediate return is required, then call 'TcpClient_read_stop_async()'. */ void TcpClient_read_stop(TcpClient* client) { if(!client)return; if(client->flag_pole & THREAD_CREATED) { flag_raise(&client->flag_pole, THREAD_STOP); pthread_join(client->read_thread, NULL); flag_lower(&client->flag_pole, THREAD_CREATED); } else if(client->flag_pole & THREAD_IS_RUNNING) TcpClient_read_thread_wait(client); }
/* Function used to start listening to client events on a separate * thread. */ static void* threaded_run(void* v_listener) { ClientListener* listener = (ClientListener*)v_listener; flag_raise(&listener->flag_pole, THREAD_IS_RUNNING); flag_lower(&listener->flag_pole, THREAD_STOP); listen_loop(listener); flag_lower(&listener->flag_pole, THREAD_IS_RUNNING); /* Epoll is no longer in use, we should close * the file descriptor. */ close_epoll_tsafe(listener); return(NULL); }
/* Disconnects the client and destroys the object. */ void delTcpClient(TcpClient** client) { if(!client || !*client || ((*client)->flag_pole & OBJECT_DELETE_STATE))return; /* Place the object in a delete state. */ flag_raise(&(*client)->flag_pole, OBJECT_DELETE_STATE); TcpClient_disconnect(*client); if((*client)->free_data_cb) (*client)->free_data_cb((*client)->ex_data); free(*client); client = NULL; }
/* Starts clients in the ClientListener on a separate thread. The * thread is managed internally and can be stopped by calling * 'ClientListener_stop()' or 'delClientListener()'. * * Returns: * ALIB_OK: Thread is already running, or thread was started without error. * Any error that occurs after this was raised in the listen loop. * Anything else: Error code related to the error. */ alib_error ClientListener_start_async(ClientListener* listener) { if(!listener)return(ALIB_BAD_ARG); int err = ALIB_OK; /* Check to see if the thread is running. */ if(listener->flag_pole & THREAD_IS_RUNNING) { /* If we are supposed to stop the thread, then stop the * ClientListener. */ if(listener->flag_pole & THREAD_STOP) ClientListener_stop(listener); /* Otherwise, the thread is already running, there is nothing to do. */ else return(ALIB_OK); } flag_lower(&listener->flag_pole, THREAD_STOP); /* Initialize the epoll. */ err = init_epoll_tsafe(listener); if(err) return(err); /* Add the clients to the epoll. */ err = add_clients_to_epoll_tsafe(listener); if(err)goto f_error; /* Create the thread. */ if(listener->flag_pole & THREAD_CREATED) pthread_join(listener->thread, NULL); else flag_raise(&listener->flag_pole, THREAD_CREATED); if(pthread_create(&listener->thread, NULL, threaded_run, listener)) { /* If creation failed, then we need to return an error. */ flag_lower(&listener->flag_pole, THREAD_CREATED); err = ALIB_THREAD_ERR; goto f_error; } return(ALIB_OK); f_error: ClientListener_stop(listener); return(err); }
/* Starts the thread. If the thread is already running * ALIB_OK will be returned. * * Waiting for child processes to close is handled on a separate thread. */ alib_error proc_waiter_start() { int err = allocate_globals(); if(err)return(err); /* Make sure we don't call start at the same time from two different threads. */ pthread_mutex_lock(PROC_WAITER_MUTEX); /* Setup the flags as needed. */ flag_lower(&PROC_WAITER_FLAG_POLE, THREAD_STOP); if((PROC_WAITER_FLAG_POLE & THREAD_IS_RUNNING) && (PROC_WAITER_FLAG_POLE & THREAD_CREATED)) { err = ALIB_OK; goto f_unlock; } /* Check to see if we are still running. */ if(PROC_WAITER_FLAG_POLE & THREAD_IS_RUNNING) proc_waiter_stop_now(); /* Ensure our thread is cleaned up. */ if(PROC_WAITER_FLAG_POLE & THREAD_CREATED) pthread_join(*PROC_WAITER_THREAD, NULL); /* Raise the THREAD_IS_RUNNING flag before creating the thread so that the flag * will never misrepresent the state of the thread. */ flag_raise(&PROC_WAITER_FLAG_POLE, THREAD_IS_RUNNING | THREAD_CREATED); if(pthread_create(PROC_WAITER_THREAD, NULL, thread_proc, NULL)) { flag_lower(&PROC_WAITER_FLAG_POLE, THREAD_IS_RUNNING | THREAD_CREATED); err = ALIB_THREAD_ERR; goto f_unlock; } f_unlock: pthread_mutex_unlock(PROC_WAITER_MUTEX); return(err); }
/* Stops a currently running ClientListener object. If the object * is already stopped, nothing will happen. * * This should be called whenever the object is no longer running. */ alib_error ClientListener_stop(ClientListener* listener) { if(!listener)return(ALIB_BAD_ARG); /* Set the stop flag for the thread. */ if(listener->flag_pole & THREAD_IS_RUNNING) flag_raise(&listener->flag_pole, THREAD_STOP); /* Close the epoll socket to break epoll_wait(). */ close_epoll_tsafe(listener); /* If a thread has been created, join it. */ if(listener->flag_pole & THREAD_CREATED) { pthread_cond_broadcast(&listener->t_cond); pthread_join(listener->thread, NULL); flag_lower(&listener->flag_pole, THREAD_CREATED); } return(ALIB_OK); }
/* Called whenever a client is removed from the array list. */ static void remove_client_cb(void* v_sock_pack) { socket_package* sp = (socket_package*)v_sock_pack; ClientListener* listener = (ClientListener*)sp->parent; /* Call the server's client disconnected callback. */ if(listener->disconnected) { int rval = listener->disconnected(listener, sp); if(rval & SCB_RVAL_STOP_SERVER) { flag_raise(&listener->flag_pole, THREAD_STOP); close(listener->ep.efd); listener->ep.efd = -1; } } /* Free the socket package. */ close_and_free_socket_package(sp); pthread_cond_broadcast(&listener->t_cond); }
task main() { waitForStart(); while (true) { getJoystickSettings(joystick); //driver controls int cont1_left_yval = avoidWeird(joystick.joy1_y1, 20); //y coordinate for the left joystick on controller 1 int cont1_left_xval = avoidWeird(joystick.joy1_x1, 75); //x coordinate for the left joystick on controller 1 int cont1_right_yval = avoidWeird(joystick.joy1_y2, 20); //y coordinate for the right joystick on controller 1 //arm/hand controls int cont2_right_yval = avoidWeird(joystick.joy2_y2, 20); int cont2_left_yval = avoidWeird(joystick.joy2_y1, 20); //int cont1_dPad = joystick.joy1_TopHat; //Value of the dPad for controller 2 drive(cont1_left_yval, cont1_left_xval); shoulderMovement(cont2_right_yval); handMovement(cont2_left_yval); flag_raise(cont1_right_yval); } }
/* Starts the reading process on the client. */ alib_error TcpClient_read_start(TcpClient* client) { if(!client)return(ALIB_BAD_ARG); else if((client->flag_pole & THREAD_IS_RUNNING) && !(client->flag_pole & THREAD_STOP)) return(ALIB_OK); /* Thread has been called to stop, but hasn't yet. */ else TcpClient_read_stop(client); if(client->data_in_cb && client->sock >= 0) { flag_lower(&client->flag_pole, THREAD_STOP); flag_raise(&client->flag_pole, THREAD_CREATED); if(pthread_create(&client->read_thread, NULL, read_loop_proc, client)) { flag_lower(&client->flag_pole, THREAD_CREATED); return(ALIB_THREAD_ERR); } } return(ALIB_OK); }
/*******Private Functions*******/ static void* thread_proc(void* unused) { int status; int pid; proc_waiter** pw_it; size_t pw_it_count; if(!proc_waiter_is_initialized()) return(NULL); flag_raise(&PROC_WAITER_FLAG_POLE, THREAD_IS_RUNNING); while(PROC_WAITER_CB_LIST && !(PROC_WAITER_FLAG_POLE & THREAD_STOP)) { #ifdef __ANDROID__ pid = wait(&status); #else pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pid = wait(&status); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); #endif /* There are no child processes connected to the current process. */ if(pid < 0) { pthread_mutex_lock(PROC_WAITER_MUTEX); if(!PROC_WAITER_CB_LIST) { pthread_mutex_unlock(PROC_WAITER_MUTEX); break; } if(!ArrayList_get_count(PROC_WAITER_CB_LIST)) { while(PROC_WAITER_CB_LIST && !ArrayList_get_count(PROC_WAITER_CB_LIST) && !(PROC_WAITER_FLAG_POLE & THREAD_STOP)) { pthread_cond_wait(PROC_WAITER_T_COND, PROC_WAITER_MUTEX); } } else if(PROC_WAITER_SLEEP_TIME < 0) pthread_cond_wait(PROC_WAITER_T_COND, PROC_WAITER_MUTEX); else { struct timespec sleepTo; clock_gettime(CLOCK_REALTIME, &sleepTo); sleepTo.tv_nsec += PROC_WAITER_SLEEP_TIME; timespec_fix_values(&sleepTo); pthread_cond_timedwait(PROC_WAITER_T_COND, PROC_WAITER_MUTEX, &sleepTo); } pthread_mutex_unlock(PROC_WAITER_MUTEX); } else { /* Iterate through the list and call the registered callbacks. */ ArrayList_lock(PROC_WAITER_CB_LIST); for(pw_it = (proc_waiter**)ArrayList_get_array_ptr(PROC_WAITER_CB_LIST), pw_it_count = 0; pw_it_count < ArrayList_get_count(PROC_WAITER_CB_LIST);++pw_it) { if(*pw_it) { ++pw_it_count; /* Call the registered callback. */ if(((*pw_it)->pid < 0 || (*pw_it)->pid == pid)) { if((*pw_it)->cb) (*pw_it)->cb(pid, status, (*pw_it)->user_data); /* Deregister an event callback if the pid is not a wildcard * number. Check 'pw_it' again to ensure it wasn't deleted in * the callback. */ if(*pw_it && (*pw_it)->pid > -1) ArrayList_remove_by_ptr(PROC_WAITER_CB_LIST, (void**)pw_it); } } } ArrayList_unlock(PROC_WAITER_CB_LIST); } } flag_lower(&PROC_WAITER_FLAG_POLE, THREAD_IS_RUNNING); pthread_cond_broadcast(PROC_WAITER_T_COND); return(NULL); }
/* Calls receive on the client's socket until either an error happens * or the socket is closed. */ static void* read_loop_proc(void* void_client) { TcpClient* client = (TcpClient*)void_client; char in_buff[64 * 1024]; int in_count; int rval; struct timeval tv; socklen_t tv_len = sizeof(tv); flag_raise(&client->flag_pole, THREAD_IS_RUNNING); pthread_cond_broadcast(&client->read_cond); /* Ensure there is a timeout set for the socket. If one does not * exist, then set the timeout to 1 second. */ if(getsockopt(client->sock, SOL_SOCKET, SO_RCVTIMEO, &tv, &tv_len)) goto f_return; if(!tv.tv_sec && !tv.tv_usec) { tv.tv_sec = 1; if(setsockopt(client->sock, SOL_SOCKET, SO_RCVTIMEO, &tv, tv_len)) goto f_return; } while(!(client->flag_pole & THREAD_STOP) && client->sock > -1 && client->data_in_cb) { /* Wait for data. */ in_count = recv(client->sock, in_buff, sizeof(in_buff), 0); /* Disconnected/error occurred. */ if(in_count <= 0) { if(errno == EWOULDBLOCK) { errno = 0; continue; } else { /* We can't call 'TcpClient_disconnect()' if the object is in a delete * state because it has already been called. */ if(!(client->flag_pole & OBJECT_DELETE_STATE)) TcpClient_disconnect(client); break; } } /* Data received. */ else { rval = client->data_in_cb(client, in_buff, in_count); if(rval & (SCB_RVAL_CLOSE_CLIENT | SCB_RVAL_STOP_SERVER)) TcpClient_disconnect(client); if(rval & (SCB_RVAL_DELETE)) { pthread_detach(client->read_thread); flag_lower(&client->flag_pole, THREAD_CREATED); delTcpClient(&client); } } } f_return: flag_lower(&client->flag_pole, THREAD_IS_RUNNING); pthread_cond_broadcast(&client->read_cond); if(client->thread_returning_cb) client->thread_returning_cb(client); return(NULL); }
/* The main listening loop for the object. */ static alib_error listen_loop(ClientListener* listener) { if(!listener)return(ALIB_BAD_ARG); int rval; int event_count; struct epoll_event* event_it; long data_in_count; void* data_in_buff = malloc(DEFAULT_INPUT_BUFF_SIZE); /* Ensure we were able to allocate the data in buffer. */ if(!data_in_buff) { rval = ALIB_MEM_ERR; goto f_return; } /* While our socket is open, then we will keep running. */ while(!(listener->flag_pole & THREAD_STOP)) { /* If the array list is empty, then we simply wait until something is added * to it or our thread is called to stop. */ if(!ArrayList_get_count(listener->client_list)) { /* Call the empty list callback. */ if(listener->client_list_empty) { int rval = listener->client_list_empty(listener); if(rval & SCB_RVAL_STOP_SERVER) break; } pthread_mutex_lock(&listener->mutex); while(!ArrayList_get_count(listener->client_list) && !(listener->flag_pole & THREAD_STOP)) pthread_cond_wait(&listener->t_cond, &listener->mutex); pthread_mutex_unlock(&listener->mutex); continue; } /* Wait for an event to come. */ event_count = epoll_wait(listener->ep.efd, listener->ep.triggered_events, DEFAULT_BACKLOG_SIZE, 1000); if(!event_count)continue; /* The the event_count is less than zero, then an error occurred. */ if(event_count < 0) { if(listener->flag_pole & THREAD_STOP) rval = ALIB_OK; else { if(listener->ep.efd > -1) continue; rval = ALIB_CHECK_ERRNO; } goto f_return; } /* Iterate through the events. */ if(pthread_mutex_lock(&listener->mutex)) { rval = ALIB_MUTEX_ERR; goto f_return; } for(event_it = listener->ep.triggered_events; event_count > 0; ++event_it, --event_count) { /* Use compare_int_ptr as the first member in the socket package * is an integer. */ socket_package* client = (socket_package*)ArrayList_find_item_by_value_tsafe( listener->client_list, &event_it->data.fd, compare_int_ptr); if(!client) { close(listener->ep.triggered_events->data.fd); continue; } /* Error occurred on the socket. */ if((event_it->events & (EPOLLERR | EPOLLHUP)) || !(event_it->events & EPOLLIN)) { ArrayList_remove_tsafe(listener->client_list, client); continue; } /* Call the client_data_ready callback. */ if(listener->data_ready) { rval = listener->data_ready(listener, client, &data_in_buff, &data_in_count); if(rval & SCB_RVAL_CLOSE_CLIENT) ArrayList_remove_tsafe(listener->client_list, client); if(rval & SCB_RVAL_STOP_SERVER) { rval = ALIB_OK; flag_raise(&listener->flag_pole, THREAD_STOP); if(pthread_mutex_unlock(&listener->mutex)) rval = ALIB_MUTEX_ERR; goto f_return; } if(rval & (SCB_RVAL_HANDLED | SCB_RVAL_CLOSE_CLIENT)) continue; } else { data_in_count = recv(client->sock, data_in_buff, DEFAULT_INPUT_BUFF_SIZE, 0); } /* If the client's socket was closed, then we just remove it * from the list. */ if(data_in_count < 1) ArrayList_remove_tsafe(listener->client_list, client); /* Call the client data in callback. */ else if(listener->data_in) { rval = listener->data_in(listener, client, data_in_buff, data_in_count); if(rval & SCB_RVAL_CLOSE_CLIENT) ArrayList_remove_tsafe(listener->client_list, client); if(rval & SCB_RVAL_STOP_SERVER) { rval = ALIB_OK; if(pthread_mutex_unlock(&listener->mutex)) rval = ALIB_MUTEX_ERR; goto f_return; } } } if(pthread_mutex_unlock(&listener->mutex)) { rval = ALIB_MUTEX_ERR; goto f_return; } } rval = ALIB_OK; f_return: if(data_in_buff) free(data_in_buff); return(rval); }