diff --git a/libisoburn/libisoburn.ver b/libisoburn/libisoburn.ver index 176ee8df..f2449fd4 100644 --- a/libisoburn/libisoburn.ver +++ b/libisoburn/libisoburn.ver @@ -300,7 +300,9 @@ Xorriso_pull_outlists; Xorriso_push_outlists; Xorriso_read_rc; Xorriso_set_problem_status; +Xorriso_start_msg_watcher; Xorriso_startup_libraries; +Xorriso_stop_msg_watcher; local: *; }; diff --git a/xorriso/aux_objects.c b/xorriso/aux_objects.c index cd43c62d..f0245bf7 100644 --- a/xorriso/aux_objects.c +++ b/xorriso/aux_objects.c @@ -656,6 +656,19 @@ int Xorriso_lst_get_last(struct Xorriso_lsT *entry, struct Xorriso_lsT **last, } +int Xorriso_lst_concat(struct Xorriso_lsT *first, struct Xorriso_lsT *second, + int flag) +{ + struct Xorriso_lsT *last; + + Xorriso_lst_get_last(first, &last, 0); + if(last != NULL) + last->next= second; + if(second != NULL) + second->prev= last; + return(1); +} + /* --------------------------- End Xorriso_lsT ---------------------------- */ diff --git a/xorriso/aux_objects.h b/xorriso/aux_objects.h index 3a59a4af..a2be3a72 100644 --- a/xorriso/aux_objects.h +++ b/xorriso/aux_objects.h @@ -133,6 +133,9 @@ int Xorriso_lst_detach_text(struct Xorriso_lsT *entry, int flag); int Xorriso_lst_get_last(struct Xorriso_lsT *entry, struct Xorriso_lsT **last, int flag); +int Xorriso_lst_concat(struct Xorriso_lsT *first, struct Xorriso_lsT *second, + int flag); + int Exclusions_new(struct ExclusionS **o, int flag); diff --git a/xorriso/base_obj.c b/xorriso/base_obj.c index fb08c9c3..38bc4e0d 100644 --- a/xorriso/base_obj.c +++ b/xorriso/base_obj.c @@ -321,6 +321,11 @@ int Xorriso_new(struct XorrisO ** xorriso,char *progname, int flag) m->lib_msg_queue_lock_ini= 0; m->result_msglists_lock_ini= 0; m->write_to_channel_lock_ini= 0; + m->msg_watcher_lock_ini= 0; + m->msg_watcher_state= 0; + m->msgw_result_handler= NULL; + m->msgw_info_handler= NULL; + m->msgw_stack_handle= -1; m->msglist_stackfill= 0; m->status_history_max= Xorriso_status_history_maX; m->scsi_log= 0; @@ -454,6 +459,10 @@ int Xorriso_new(struct XorrisO ** xorriso,char *progname, int flag) if(ret != 0) goto failure; m->problem_status_lock_ini= 1; + ret= pthread_mutex_init(&(m->msg_watcher_lock), NULL); + if(ret != 0) + goto failure; + m->msg_watcher_lock_ini= 1; if(leafname != NULL) free(leafname); @@ -545,6 +554,8 @@ int Xorriso_destroy(struct XorrisO **xorriso, int flag) pthread_mutex_destroy(&(m->write_to_channel_lock)); if(m->problem_status_lock_ini) pthread_mutex_destroy(&(m->problem_status_lock)); + if(m->msg_watcher_lock_ini) + pthread_mutex_destroy(&(m->msg_watcher_lock)); free((char *) m); *xorriso= NULL; diff --git a/xorriso/parse_exec.c b/xorriso/parse_exec.c index 6bdee93f..88005661 100644 --- a/xorriso/parse_exec.c +++ b/xorriso/parse_exec.c @@ -1724,7 +1724,57 @@ next_command:; } else if(strcmp(cmd,"test")==0) { /* This option does not exist. */ /* install temporary test code here */; +/* Test setup for for Xorriso_push_outlists() et.al. */ { + int stack_handle = -1, line_count; + struct Xorriso_lsT *result_list, *info_list; + int Xorriso_process_msg_lists(struct XorrisO *xorriso, + struct Xorriso_lsT *result_list, + struct Xorriso_lsT *info_list, + int *line_count, int flag); + + (*idx)++; + if(strcmp(arg1, "push") == 0) { + ret= Xorriso_push_outlists(xorriso, &stack_handle, 3); + fprintf(stderr, "xorriso -test: Xorriso_push() = %d, handle = %d\n", + ret, stack_handle); + } else if(strcmp(arg1, "pull") == 0) { + ret= Xorriso_pull_outlists(xorriso, -1, &result_list, &info_list, 0); + fprintf(stderr, "xorriso -test: Xorriso_push() = %d, handle = %d\n", + ret, stack_handle); + if(ret > 0) { + ret= Xorriso_process_msg_lists(xorriso, result_list, info_list, + &line_count, 0); + fprintf(stderr, + "xorriso -test: Xorriso_process_msg_lists() = %d, line_count = %d\n", + ret, line_count); + } + } else if(strcmp(arg1, "fetch") == 0) { + ret= Xorriso_fetch_outlists(xorriso, -1, &result_list, &info_list, 0); + fprintf(stderr, "xorriso -test: Xorriso_fetch() = %d, handle = %d\n", + ret, stack_handle); + if(ret > 0) { + ret= Xorriso_process_msg_lists(xorriso, result_list, info_list, + &line_count, 0); + fprintf(stderr, + "xorriso -test: Xorriso_process_msg_lists() = %d, line_count = %d\n", + ret, line_count); + } + } else if(strcmp(arg1, "start") == 0) { + ret= Xorriso_start_msg_watcher(xorriso, NULL, NULL, 0); + fprintf(stderr, "xorriso -test: Xorriso_start_msg_watcher() = %d\n", ret); + } else if(strcmp(arg1, "stop") == 0) { + ret= Xorriso_stop_msg_watcher(xorriso, 0); + fprintf(stderr, "xorriso -test: Xorriso_stop_msg_watcher() = %d\n", ret); + } else { + fprintf(stderr, "xorriso -test: unknwon mode: %s\n", arg1); + } + ret= 0; +} + + +/* Test setup for Xorriso_parse_line */ +if(0){ int pargc, pflag, max_words; char **pargv= NULL, *pline, *prefix, *separators; diff --git a/xorriso/text_io.c b/xorriso/text_io.c index 473d0ec4..16a4e626 100644 --- a/xorriso/text_io.c +++ b/xorriso/text_io.c @@ -906,19 +906,30 @@ int Xorriso_pull_outlists(struct XorrisO *xorriso, int stack_handle, if(ret > 0) locked= 1; + if(stack_handle == -1) + stack_handle= xorriso->msglist_stackfill - 1; if(stack_handle < 0 || stack_handle >= xorriso->msglist_stackfill) { Xorriso_msgs_submit(xorriso, 0, "Program error: Wrong message output redirection stack handle", 0, "FATAL", 0); ret= -1; goto ex; } - *result_list= xorriso->result_msglists[stack_handle]; - *info_list= xorriso->info_msglists[stack_handle]; - for(i = stack_handle + 1; i < xorriso->msglist_stackfill - 1; i++) { - xorriso->result_msglists[i - 1]= xorriso->result_msglists[i]; - xorriso->info_msglists[i - 1]= xorriso->info_msglists[i]; + + /* Concatenate all redirections above stack_handle */ + *result_list= NULL; + *info_list= NULL; + for(i = stack_handle; i < xorriso->msglist_stackfill; i++) { + if(*result_list == NULL) + *result_list= xorriso->result_msglists[i]; + else + Xorriso_lst_concat(*result_list, xorriso->result_msglists[i], 0); + if(*info_list == NULL) + *info_list= xorriso->info_msglists[i]; + else + Xorriso_lst_concat(*info_list, xorriso->info_msglists[i], 0); } - xorriso->msglist_stackfill--; + xorriso->msglist_stackfill= stack_handle; + ret= 1; ex:; if(locked) @@ -927,6 +938,260 @@ ex:; } +int Xorriso_result_handler_stdout(struct XorrisO *xorriso, char *text) +{ + printf("%s", text); + fflush(stdout); + return(1); +} + + +int Xorriso_info_handler_stderr(struct XorrisO *xorriso, char *text) +{ + if(xorriso->stderr_fp != NULL) { + fprintf(xorriso->stderr_fp, "%s", text); + fflush(xorriso->stderr_fp); + } else { + fprintf(stderr, "%s", text); + fflush(stderr); + } + return(1); +} + + +int Xorriso_process_msg_lists(struct XorrisO *xorriso, + struct Xorriso_lsT *result_list, + struct Xorriso_lsT *info_list, + int *line_count, int flag) +{ + struct Xorriso_lsT *lpt; + int ret; + int (*handler)(struct XorrisO *xorriso, char *text); + + handler= xorriso->msgw_result_handler; + if(handler == NULL) + handler= Xorriso_result_handler_stdout; + for(lpt= result_list; lpt != NULL; lpt= lpt->next) { + (*line_count)++; + ret= (*handler)(xorriso, Xorriso_lst_get_text(lpt, 0)); + if(ret < 0) + return(-1); + } + handler= xorriso->msgw_info_handler; + if(handler == NULL) + handler= Xorriso_info_handler_stderr; + for(lpt= info_list; lpt != NULL; lpt= lpt->next) { + (*line_count)++; + ret= (*handler)(xorriso, Xorriso_lst_get_text(lpt, 0)); + if(ret < 0) + return(-1); + } + return(1); +} + + +static void *Xorriso_msg_watcher(void *state_pt) +{ + struct XorrisO *xorriso; + int ret, u_wait= 10000, line_count, sleep_thresh= 20; + struct Xorriso_lsT *result_list= NULL, *info_list= NULL; + static int debug_sev= 0; + + xorriso= (struct XorrisO *) state_pt; + + if(debug_sev == 0) + Xorriso__text_to_sev("DEBUG", &debug_sev, 0); + + xorriso->msg_watcher_state= 2; + if(xorriso->msgw_info_handler != NULL && + debug_sev < xorriso->report_about_severity && + debug_sev < xorriso->abort_on_severity) + (*xorriso->msgw_info_handler)(xorriso, + "xorriso : DEBUG : Concurrent message watcher started\n"); + while(1) { + line_count= 0; + + /* Watch out for end request in xorriso */ + if(xorriso->msg_watcher_state == 3) + break; + + ret= Xorriso_fetch_outlists(xorriso, -1, &result_list, &info_list, 3); + if(ret < 0) + break; + if(ret > 0) { + /* Process fetched lines */ + ret= Xorriso_process_msg_lists(xorriso, result_list, info_list, + &line_count, 0); + Xorriso_lst_destroy_all(&result_list, 0); + Xorriso_lst_destroy_all(&info_list, 0); + if(ret < 0) + break; + } + + if(line_count < sleep_thresh) + usleep(u_wait); + } + if(xorriso->msgw_info_handler != NULL && + debug_sev < xorriso->report_about_severity && + debug_sev < xorriso->abort_on_severity) + (*xorriso->msgw_info_handler)(xorriso, + "xorriso : DEBUG : Concurrent message watcher ended\n"); + xorriso->msg_watcher_state= 0; + return(NULL); +} + + +int Xorriso_start_msg_watcher(struct XorrisO *xorriso, + int (*result_handler)(struct XorrisO *xorriso, char *text), + int (*info_handler)(struct XorrisO *xorriso, char *text), + int flag) +{ + int ret, u_wait= 1000, locked= 0, pushed= 0, uret, line_count= 0; + struct Xorriso_lsT *result_list= NULL, *info_list= NULL; + pthread_attr_t attr; + pthread_attr_t *attr_pt = NULL; + pthread_t thread; + + ret= pthread_mutex_lock(&(xorriso->msg_watcher_lock)); + if(ret != 0) { + Xorriso_msgs_submit(xorriso, 0, + "Cannot aquire mutex lock for managing concurrent message watcher", + ret, "FATAL", 0); + ret= -1; goto ex; + } + locked= 1; + + /* Check for running watcher */ + if(xorriso->msg_watcher_state > 0) { + sprintf(xorriso->info_text, + "There is already a concurrent message watcher running"); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0); + ret= 0; goto ex; + } + + ret= Xorriso_push_outlists(xorriso, &(xorriso->msgw_stack_handle), 3); + if(ret <= 0) + goto ex; + pushed= 1; + + /* Register watcher */ + xorriso->msgw_result_handler= result_handler; + xorriso->msgw_info_handler= info_handler; + xorriso->msg_watcher_state= 1; + + /* Start thread */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + attr_pt= &attr; + ret= pthread_create(&thread, attr_pt, Xorriso_msg_watcher, xorriso); + if(ret != 0) { + sprintf(xorriso->info_text, + "Cannot create thread for concurrent message watcher"); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0); + ret= 0; goto ex; + } + + /* Wait until watcher has indicated start */ + while(xorriso->msg_watcher_state == 1) { + + /* >>> have a timeout ? */; + + usleep(u_wait); + } + + ret= 1; +ex:; + if(ret <= 0 && pushed) { + uret= Xorriso_pull_outlists(xorriso, xorriso->msgw_stack_handle, + &result_list, &info_list, 0); + if(uret > 0) { + xorriso->msgw_result_handler= NULL; + xorriso->msgw_info_handler= NULL; + Xorriso_process_msg_lists(xorriso, result_list, info_list, + &line_count, 0); + Xorriso_lst_destroy_all(&result_list, 0); + Xorriso_lst_destroy_all(&info_list, 0); + } + } + if(locked) { + uret= pthread_mutex_unlock(&(xorriso->msg_watcher_lock)); + if(uret != 0) { + Xorriso_msgs_submit(xorriso, 0, + "Cannot release mutex lock for managing concurrent message watcher", + uret, "FATAL", 0); + ret= -1; + } + } + return(ret); +} + + +/* @param flag bit0= do not complain loudly if no wather is active +*/ +int Xorriso_stop_msg_watcher(struct XorrisO *xorriso, int flag) +{ + int ret, u_wait= 1000, locked= 0, uret, line_count= 0; + struct Xorriso_lsT *result_list= NULL, *info_list= NULL; + + if((flag & 1) && xorriso->msg_watcher_state != 2) + /* Roughly tolerate non-running watcher */ + {ret= 0; goto ex;} + + ret= pthread_mutex_lock(&(xorriso->msg_watcher_lock)); + if(ret != 0) { + Xorriso_msgs_submit(xorriso, 0, + "Cannot aquire mutex lock for managing concurrent message watcher", + ret, "FATAL", 0); + ret= -1; goto ex; + } + locked= 1; + + /* Check for running watcher */ + if(xorriso->msg_watcher_state != 2) { + sprintf(xorriso->info_text, + "There is no concurrent message watcher running"); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "SORRY", 0); + ret= 0; goto ex; + } + + /* Inform watcher of desire to stop it */ + xorriso->msg_watcher_state= 3; + + /* Wait until watcher has indicated its end */ + while(xorriso->msg_watcher_state != 0) { + + /* >>> have a timeout ? */; + + usleep(u_wait); + } + + ret= Xorriso_pull_outlists(xorriso, xorriso->msgw_stack_handle, + &result_list, &info_list, 0); + if(ret > 0) { + Xorriso_process_msg_lists(xorriso, result_list, info_list, + &line_count, 0); + Xorriso_lst_destroy_all(&result_list, 0); + Xorriso_lst_destroy_all(&info_list, 0); + } + + xorriso->msgw_result_handler= NULL; + xorriso->msgw_info_handler= NULL; + + ret= 1; +ex:; + if(locked) { + uret= pthread_mutex_unlock(&(xorriso->msg_watcher_lock)); + if(uret != 0) { + Xorriso_msgs_submit(xorriso, 0, + "Cannot release mutex lock for managing concurrent message watcher", + uret, "FATAL", 0); + ret= -1; + } + } + return(ret); +} + + int Xorriso_result(struct XorrisO *xorriso, int flag) /* bit0= no considerations or computations or dialog. Just put out. diff --git a/xorriso/xorriso.h b/xorriso/xorriso.h index b93ea6a7..698ab2ba 100644 --- a/xorriso/xorriso.h +++ b/xorriso/xorriso.h @@ -580,8 +580,9 @@ struct Xorriso_lsT; and the Xorriso_option_pkt_output() protocol will not be applied. @param xorriso The environment handle @param stack_handle returns an id number which is unique as long as - its redirection is stacked. It may be re-used after - its redirection was pulled from the stack. + its redirection is stacked. Do not interpret it and + do not use it after its redirection was pulled from + the stack. @param flag Bitfield for control purposes bit0= redirect result channel bit1= redirect info channel @@ -635,6 +636,7 @@ int Xorriso_fetch_outlists(struct XorrisO *xorriso, int stack_handle, @param stack_handle An id number returned by Xorriso_push_outlists() and not yet revoked by Xorriso_pull_outlists(). This handle is invalid after the call. + Submit -1 to address the most recent valid id. @param result_list Result and mark messages (usually directed to stdout) @param info_list Info and mark messages (usually directed to stderr) @param flag unused yet, submit 0 @@ -645,6 +647,46 @@ int Xorriso_pull_outlists(struct XorrisO *xorriso, int stack_handle, struct Xorriso_lsT **info_list, int flag); +/** Redirect output by Xorriso_push_outlists() and start a thread which + fetches this output and performs a call of a given function with each + message that is obtained. + @since 1.2.6 + @param xorriso The environment handle + @param result_handler Pointer to the function which shall be called with + each result message. A NULL pointer causes output + to be directed to stdout. + The function should use the pointer xorriso with + outmost caution, because nearly all API calls are not + thread-safe and may not be used. Best is to use it + only to distinguish the callers if more than one + struct XorrisO is in use by the application. + @param info_handler Pointer to the function which shall be called with + each info message. A NULL pointer causes output to + be directed to stderr resp. to -as mkisofs -log-file. + The same caution is needed as with result_handler. + @param flag unused yet, submit 0 + @return 1 on success, <=0 if failure (e.g. there is already + a watcher active) +*/ +int Xorriso_start_msg_watcher(struct XorrisO *xorriso, + int (*result_handler)(struct XorrisO *xorriso, char *text), + int (*info_handler)(struct XorrisO *xorriso, char *text), + int flag); + + +/** Revoke output redirection by Xorriso_start_msg_watcher() and end the + watcher thread. If text messages are delivered when Xorriso_pull_outlists() + is called, then they get put out through the active handler functions. + @since 1.2.6 + @param xorriso The environment handle + @param flag Bitfield for control purposes: + bit0= do not issue SORRY message if no message + watcher is active + @return 1 on success, <=0 if failure +*/ +int Xorriso_stop_msg_watcher(struct XorrisO *xorriso, int flag); + + /** Obtain the text message from the current list item. @param entry The current list item @param flag unused yet, submit 0 diff --git a/xorriso/xorriso_main.c b/xorriso/xorriso_main.c index da7b8f01..63cfb917 100644 --- a/xorriso/xorriso_main.c +++ b/xorriso/xorriso_main.c @@ -274,6 +274,7 @@ int main(int argc, char **argv) {ret= 6; goto emergency_exit;} end_successfully:; /* normal shutdown, including eventual -commit */ + Xorriso_stop_msg_watcher(xorriso, 1); Xorriso_process_msg_queues(xorriso, 0); if(Xorriso_change_is_pending(xorriso, 1)) Xorriso_option_end(xorriso, 2); diff --git a/xorriso/xorriso_private.h b/xorriso/xorriso_private.h index d71e9941..e02ef7c3 100644 --- a/xorriso/xorriso_private.h +++ b/xorriso/xorriso_private.h @@ -575,6 +575,17 @@ struct XorrisO { /* the global context of xorriso */ int write_to_channel_lock_ini; pthread_mutex_t write_to_channel_lock; + int msg_watcher_lock_ini; + pthread_mutex_t msg_watcher_lock; + int msg_watcher_state; /* 0= inactive + 1= registered + 2= started + 3= request to end + */ + int (*msgw_result_handler)(struct XorrisO *xorriso, char *text); + int (*msgw_info_handler)(struct XorrisO *xorriso, char *text); + int msgw_stack_handle; + int status_history_max; /* for -status long_history */ /* 0= no logging of SCSI commands, 1= to stderr */ diff --git a/xorriso/xorriso_timestamp.h b/xorriso/xorriso_timestamp.h index 78082adb..804617ef 100644 --- a/xorriso/xorriso_timestamp.h +++ b/xorriso/xorriso_timestamp.h @@ -1 +1 @@ -#define Xorriso_timestamP "2012.09.13.130910" +#define Xorriso_timestamP "2012.09.14.175104"