/*! \brief signal_read_rtvars_thread() is thread which fires off the read msg to get a new set of realtiem variables. It does so by queing messages to a thread which handles I/O. This function will check the queue depth and if the queue is backed up it will skip sending a request for data, as that will only aggravate the queue roadblock. \returns 0 on signal to exit */ G_MODULE_EXPORT void * signal_read_rtvars_thread(gpointer data) { static void (*signal_read_rtvars)(void); static gboolean (*setup_rtv)(void); static gboolean (*teardown_rtv)(void); Serial_Params *serial_params; GMutex * mutex = g_mutex_new(); GTimeVal time; GAsyncQueue *io_data_queue = NULL; GAsyncQueue *pf_dispatch_queue = NULL; GCond *rtv_thread_cond = NULL; GMutex *rtv_thread_mutex = NULL; serial_params = DATA_GET(global_data,"serial_params"); io_data_queue = DATA_GET(global_data,"io_data_queue"); pf_dispatch_queue = DATA_GET(global_data,"pf_dispatch_queue"); rtv_thread_cond = DATA_GET(global_data,"rtv_thread_cond"); rtv_thread_mutex = DATA_GET(global_data,"rtv_thread_mutex"); get_symbol("signal_read_rtvars",(void *)&signal_read_rtvars); get_symbol("setup_rtv",(void *)&setup_rtv); get_symbol("teardown_rtv",(void *)&teardown_rtv); g_return_val_if_fail(serial_params,NULL); g_return_val_if_fail(signal_read_rtvars,NULL); g_return_val_if_fail(io_data_queue,NULL); g_return_val_if_fail(pf_dispatch_queue,NULL); g_return_val_if_fail(rtv_thread_cond,NULL); g_return_val_if_fail(rtv_thread_mutex,NULL); if (setup_rtv) if (!setup_rtv()) g_thread_exit(NULL); g_mutex_lock(mutex); g_async_queue_ref(io_data_queue); g_async_queue_ref(pf_dispatch_queue); g_mutex_lock(rtv_thread_mutex); while (TRUE) { dbg_func(IO_MSG|THREADS,g_strdup(__FILE__": signal_read_rtvars_thread()\n\tsending message to thread to read RT vars\n")); signal_read_rtvars(); /* Auto-throttling if gui gets sluggish */ while (( g_async_queue_length(io_data_queue) > 2) || (g_async_queue_length(pf_dispatch_queue) > 3)) { g_get_current_time(&time); g_time_val_add(&time,1000*g_async_queue_length(pf_dispatch_queue)); if (g_cond_timed_wait(rtv_thread_cond,rtv_thread_mutex,&time)) goto breakout; } g_get_current_time(&time); g_time_val_add(&time,serial_params->read_wait*1000); if (g_cond_timed_wait(rtv_thread_cond,rtv_thread_mutex,&time)) goto breakout; } breakout: g_mutex_unlock(rtv_thread_mutex); g_async_queue_unref(io_data_queue); g_async_queue_unref(pf_dispatch_queue); g_mutex_unlock(mutex); g_mutex_free(mutex); if (teardown_rtv) teardown_rtv(); g_thread_exit(0); return NULL; }
/*! \brief Shuts down any plugin allocated resources (Serial IO/threads/queues, etc) and deallocates anything that was allocated with plugin_init(), as well as de-registering any enums specific to this plugin. This allows the plugin to be safely uninstalled */ G_MODULE_EXPORT void plugin_shutdown() { GThread *thread = NULL; GCond *cond = NULL; GAsyncQueue *queue = NULL; GHashTable *hash = NULL; GMutex *mutex = NULL; gint id = 0; ENTER(); teardown_rtv(); freeems_serial_disable(); thread = (GThread *)DATA_GET(global_data,"packet_handler_thread"); if (thread) { DATA_SET(global_data,"packet_handler_thread_exit",GINT_TO_POINTER(TRUE)); g_thread_join(thread); DATA_SET(global_data,"packet_handler_thread",NULL); DATA_SET(global_data,"packet_handler_thread_exit",NULL); } queue = (GAsyncQueue *)DATA_GET(global_data,"burn_queue"); if (queue) { deregister_packet_queue(PAYLOAD_ID,queue,RESPONSE_BURN_BLOCK_FROM_RAM_TO_FLASH); g_async_queue_unref(queue); DATA_SET(global_data,"burn_queue",NULL); queue = NULL; } queue = (GAsyncQueue *)DATA_GET(global_data,"FLASH_write_queue"); if (queue) { deregister_packet_queue(PAYLOAD_ID,queue,RESPONSE_REPLACE_BLOCK_IN_FLASH); g_async_queue_unref(queue); DATA_SET(global_data,"FLASH_write_queue",NULL); queue = NULL; } queue = (GAsyncQueue *)DATA_GET(global_data,"RAM_write_queue"); if (queue) { deregister_packet_queue(PAYLOAD_ID,queue,RESPONSE_UPDATE_BLOCK_IN_RAM); g_async_queue_unref(queue); DATA_SET(global_data,"RAM_write_queue",NULL); queue = NULL; } queue = (GAsyncQueue *)DATA_GET(global_data,"packet_queue"); if (queue) { g_async_queue_unref(queue); DATA_SET(global_data,"packet_queue",NULL); queue = NULL; } hash = (GHashTable *)DATA_GET(global_data,"payload_id_queue_hash"); if (hash) g_hash_table_destroy(hash); hash = NULL; DATA_SET(global_data,"payload_id_queue_hash",NULL); hash = (GHashTable *)DATA_GET(global_data,"sequence_num_queue_hash"); if (hash) g_hash_table_destroy(hash); hash = NULL; DATA_SET(global_data,"sequence_num_queue_hash",NULL); cond = (GCond *)DATA_GET(global_data,"packet_handler_cond"); if (cond) g_cond_free(cond); cond = NULL; DATA_SET(global_data,"packet_handler_cond",NULL); cond = (GCond *)DATA_GET(global_data,"serial_reader_cond"); if (cond) g_cond_free(cond); cond = NULL; DATA_SET(global_data,"serial_reader_cond",NULL); mutex = (GMutex *)DATA_GET(global_data,"queue_mutex"); if (mutex) g_mutex_free(mutex); DATA_SET(global_data,"queue_mutex",NULL); mutex = (GMutex *)DATA_GET(global_data,"atomic_sequence_mutex"); if (mutex) g_mutex_free(mutex); DATA_SET(global_data,"atomic_sequence_mutex",NULL); mutex = (GMutex *)DATA_GET(global_data,"rtv_subscriber_mutex"); if (mutex) g_mutex_free(mutex); DATA_SET(global_data,"rtv_subscriber_mutex",NULL); deregister_common_enums(); EXIT(); return; }