2 * src/command.c - type representing a command.
4 * Copyright 2008,2009 Martin Quinson, Malek Cherier All right reserved.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the license (GNU LGPL) which comes with this package.
10 * This file contains all the definitions of the functions related with
11 * the tesh command type.
22 #include <sys/types.h>
34 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);
37 command_start(void* p);
41 command_new(unit_t unit, context_t context, xbt_os_mutex_t mutex)
45 command = xbt_new0(s_command_t, 1);
47 /* get the context of the execution of the command */
48 if(!(command->context = context_dup(context)))
54 /* the exit code of the command is indefinite */
55 command->exit_code = INDEFINITE;
57 /* the signal of the command is indefinite */
58 command->signal = INDEFINITE_SIGNAL;
61 command->interrupted = 0;
63 /* the mutex used to safetly access to the command unit properties */
64 command->mutex = mutex;
66 command->output = xbt_strbuff_new();
68 command->pid = INDEFINITE_PID;
70 command->stat_val = -1;
72 /* set the unit of the command */
73 command->root = unit->root ? unit->root : unit;
76 /* all the commands are runned in a thread */
77 command->thread = NULL;
79 command->successeded = 0;
81 command->reader = reader_new(command);
83 if(context->input->used)
84 command->writer = writer_new(command);
86 command->writer = NULL;
88 if(context->timeout != INDEFINITE)
89 command->timer = timer_new(command);
91 command->timer = NULL;
93 command->status = cs_initialized;
94 command->reason = csr_unknown;
96 command->stdin_fd = INDEFINITE_FD;
97 command->stdout_fd = INDEFINITE_FD;
100 /* register the command */
101 xbt_os_mutex_acquire(mutex);
103 xbt_dynar_push(unit->commands, &command);
104 command->root->cmd_nb++;
105 xbt_os_mutex_release(mutex);
109 command->execlp_errno = 0;
117 command_run(command_t command)
121 INFO2("[%s] %s",command->context->pos, command->context->command_line);
127 /* start the command in a thread*/
128 if(command->context->async)
130 command->thread = xbt_os_thread_create("", command_start, command);
135 /* start the command in the main thread */
136 command_start(command);
141 command_interrupt(command);
150 command_start(void* p)
152 command_t command = (command_t)p;
153 unit_t root = command->root;
155 /* the command is started */
156 command->status = cs_started;
158 /* increment the number of started commands of the unit */
159 xbt_os_mutex_acquire(command->mutex);
160 (root->started_cmd_nb)++;
161 xbt_os_mutex_release(command->mutex);
163 /* execute the command of the test */
164 command_exec(command, command->context->command_line);
166 if(cs_in_progress == command->status)
168 /* wait the process if it is in progress */
169 command_wait(command);
171 if(cs_failed != command->status && cs_interrupted != command->status)
172 command_check(command);
175 xbt_os_mutex_acquire(command->mutex);
177 /* if it's the last command of the root unit */
178 if(!root->interrupted && root->parsed && (root->started_cmd_nb == (root->failed_cmd_nb + root->interrupted_cmd_nb + root->successeded_cmd_nb)))
180 /* first release the mutex */
182 xbt_os_mutex_release(command->mutex);
183 /* the last command release the unit */
184 xbt_os_sem_release(root->sem);
187 xbt_os_mutex_release(command->mutex);
190 /* wait the end of the timer, the reader and the writer */
191 if(command->timer && command->timer->thread)
192 timer_wait(command->timer);
194 /* wait the end of the writer */
195 if(command->writer && command->writer->thread)
196 writer_wait(command->writer);
198 /* wait the end of the reader */
199 if(command->reader && command->reader->thread)
200 reader_wait(command->reader);
209 command_exec(command_t command, const char* command_line)
212 STARTUPINFO si = {0}; /* contains the informations about the child process windows*/
213 PROCESS_INFORMATION pi = {0}; /* contains child process informations */
214 SECURITY_ATTRIBUTES sa = {0}; /* contains the security descriptor for the pipe handles */
215 HANDLE child_stdin_handle[2] = {NULL}; /* child_stdin_handle[1] <-> stdout of the child process */
216 HANDLE child_stdout_handle[2] = {NULL}; /* child_stdout_handle[0] <-> stdin of the child process */
217 HANDLE child_stderr = NULL;
219 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
220 sa.lpSecurityDescriptor = NULL; /* use default security for the pipe handles */
222 sa.bInheritHandle = TRUE; /* the pipe handles can be inherited */
224 if(!CreatePipe(&(child_stdin_handle[0]),&(child_stdin_handle[1]),&sa,0))
226 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));
228 unit_set_error(command->unit, (int)GetLastError(), 0);
231 command->status = cs_failed;
237 if(!DuplicateHandle(GetCurrentProcess(),(child_stdin_handle[1]),GetCurrentProcess(),&(child_stderr),0,TRUE,DUPLICATE_SAME_ACCESS))
239 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));
241 unit_set_error(command->unit, (int)GetLastError(), 0);
243 CloseHandle(child_stdin_handle[0]);
244 CloseHandle(child_stdin_handle[1]);
247 command->status = cs_failed;
252 if(!CreatePipe(&(child_stdout_handle[0]),&(child_stdout_handle[1]),&sa,0))
254 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));
255 unit_set_error(command->unit, (int)GetLastError(), 0);
257 CloseHandle(child_stdout_handle[0]);
258 CloseHandle(child_stdout_handle[1]);
259 CloseHandle(child_stdin_handle[0]);
260 CloseHandle(child_stdin_handle[1]);
263 command->status = cs_failed;
268 /* Read handle for read operations on the child std output. */
269 if(!DuplicateHandle(GetCurrentProcess(),(child_stdin_handle[0]),GetCurrentProcess(),&(command->stdout_fd),0,FALSE, DUPLICATE_SAME_ACCESS))
271 CloseHandle(child_stdout_handle[0]);
272 CloseHandle(child_stdout_handle[1]);
273 CloseHandle(child_stdin_handle[0]);
274 CloseHandle(child_stdin_handle[1]);
277 command->status = cs_failed;
279 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));
280 unit_set_error(command->unit, (int)GetLastError(), 0);
286 /* Write handle for write operations on the child std input. */
287 if(!DuplicateHandle(GetCurrentProcess(),(child_stdout_handle[1]),GetCurrentProcess(),&(command->stdin_fd), 0,FALSE,DUPLICATE_SAME_ACCESS))
289 CloseHandle(child_stdout_handle[0]);
290 CloseHandle(child_stdout_handle[1]);
291 CloseHandle(child_stdin_handle[0]);
292 CloseHandle(child_stdin_handle[1]);
295 command->status = cs_failed;
297 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));
299 unit_set_error(command->unit, (int)GetLastError(), 0);
305 CloseHandle(child_stdin_handle[0]);
306 CloseHandle(child_stdout_handle[1]);
310 /* launch the timer */
311 timer_time(command->timer);
316 /* launch the reader */
317 reader_read(command->reader);
323 /* launch the writer */
324 writer_write(command->writer);
327 si.cb = sizeof(STARTUPINFO);
329 si.dwFlags |= STARTF_USESTDHANDLES;
330 si.hStdOutput = child_stdin_handle[1];
331 si.hStdInput = child_stdout_handle[0];
332 si.hStdError = child_stderr;
334 /* launch the process */
348 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));
350 command_handle_failure(command,csr_create_process_function_failure);
352 unit_set_error(command->unit, (int)GetLastError(), 0);
356 /* the command is running */
357 command->status = cs_in_progress;
359 /* save the pid of the command */
360 command->pid = pi.hProcess;
362 /* close non used thread handle */
363 CloseHandle(pi.hThread);
368 /* close non used handles */
369 CloseHandle(child_stdin_handle[1]);
370 CloseHandle(child_stdout_handle[0]);
371 CloseHandle(child_stderr);
377 command_exec(command_t command, const char* command_line)
379 int child_stdin_fd[2] ;
380 int child_stdout_fd[2];
383 int rv = is_cmd(command->unit->runner->path, command->unit->runner->builtin, command_line);
390 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(rv, 0));
391 unit_set_error(command->unit, rv, 0);
395 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(rv, 1));
396 unit_set_error(command->unit, rv, 1);
399 command_handle_failure(command, csr_command_not_found);
409 if(pipe(child_stdin_fd))
411 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));
413 unit_set_error(command->unit, errno, 0);
415 command_handle_failure(command, csr_pipe_function_failed);
425 if(pipe(child_stdout_fd))
427 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));
431 close(child_stdin_fd[0]);
432 close(child_stdin_fd[1]);
435 unit_set_error(command->unit, errno, 0);
437 command_handle_failure(command, csr_pipe_function_failed);
445 if(fcntl(child_stdin_fd[1], F_SETFL, fcntl(child_stdin_fd[1], F_GETFL) | O_NONBLOCK) < 0)
448 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));
450 close(child_stdin_fd[0]);
451 close(child_stdin_fd[1]);
455 close(child_stdout_fd[0]);
456 close(child_stdout_fd[1]);
459 unit_set_error(command->unit, errno, 0);
461 command_handle_failure(command, csr_fcntl_function_failed);
467 /* to write to the child stdin */
468 command->stdin_fd = child_stdin_fd[1];
470 /* to read from the child stdout */
471 command->stdout_fd = child_stdout_fd[0];
473 /* launch the reader if any*/
475 reader_read(command->reader);
477 /* launch the writer if any */
479 writer_write(command->writer);
481 /* launch the timer if any */
483 timer_time(command->timer);
485 /* if there is a reader wait for its starting */
487 xbt_os_sem_acquire(command->reader->started);
489 /* if there is a reader wait for its ending */
491 xbt_os_sem_acquire(command->writer->written);
493 /* if there is a reader wait for its starting */
495 xbt_os_sem_acquire(command->timer->started);
497 /* update the state of the command, assume it is in progress */
498 command->status = cs_in_progress;
500 command->pid= fork();
506 close(child_stdin_fd[0]);
507 close(child_stdin_fd[1]);
512 close(child_stdout_fd[0]);
513 close(child_stdout_fd[1]);
516 ERROR2("[%s] Cannot fork the command `%s'", command->context->pos, command->context->command_line);
517 unit_set_error(command->unit, errno, 0);
518 command_handle_failure(command,csr_fork_function_failure);
525 /* close unused file descriptors */
527 close(child_stdin_fd[0]);
530 close(child_stdout_fd[1]);
535 /* close unused file descriptors */
537 close(child_stdin_fd[1]);
540 close(child_stdout_fd[0]);
544 /* redirect stdin to child_stdin_fd[0] (now fgets(), getchar() ... read from the pipe */
545 if(dup2(child_stdin_fd[0],STDIN_FILENO) < 0)
547 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));
548 command->unit->exit_code = errno;
550 unit_set_error(command->unit, errno, 0);
551 command_handle_failure(command,csr_dup2_function_failure);
554 /* close the unused file descriptor */
555 close(child_stdin_fd[0]);
561 /* redirect stdout and stderr to child_stdout_fd[1] (now printf(), perror()... write to the pipe */
562 if(dup2(child_stdout_fd[1],STDOUT_FILENO) < 0)
564 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));
566 unit_set_error(command->unit, errno, 0);
567 command_handle_failure(command, csr_dup2_function_failure);
570 if(dup2(child_stdout_fd[1], STDERR_FILENO) < 0)
572 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));
573 unit_set_error(command->unit, errno, 0);
574 command_handle_failure(command, csr_dup2_function_failure);
577 /* close the unused file descriptor */
578 close(child_stdout_fd[1]);
581 /* launch the command */
582 if(execlp("/bin/sh", "sh", "-c", command->context->command_line, NULL) < 0)
583 command->execlp_errno = errno;
591 command_wait(command_t command)
593 /* wait for the command terminaison */
596 if(WAIT_FAILED == WaitForSingleObject(command->pid, INFINITE))
598 ERROR2("[%s] Cannot wait for the child`%s'", command->context->pos, command->context->command_line);
600 unit_set_error(command->unit, (int)GetLastError(), 0);
602 command_handle_failure(command, csr_wait_failure );
603 /* TODO : see for the interruption */
607 /* don't take care of the timer or the writer or the reader failue */
608 if(cs_failed != command->status && cs_interrupted != command->status)
610 if(!GetExitCodeProcess(command->pid,&rv))
612 ERROR2("[%s] Cannot get the exit code of the process `%s'",command->context->pos, command->context->command_line);
614 unit_set_error(command->unit, (int)GetLastError(), 0);
616 command_handle_failure(command, csr_get_exit_code_process_function_failure );
619 command->stat_val = command->exit_code = rv;
625 command_wait(command_t command)
627 if(!command->execlp_errno)
629 /* let this thread wait for the child so that the main thread can detect the timeout without blocking on the wait */
630 int pid = waitpid(command->pid, &(command->stat_val), 0);
632 if(pid != command->pid)
634 ERROR2("[%s] Cannot wait for the child`%s'", command->context->pos, command->context->command_line);
636 unit_set_error(command->unit, errno, 0);
638 command_handle_failure(command, csr_waitpid_function_failure);
642 if(WIFEXITED(command->stat_val))
643 command->exit_code = WEXITSTATUS(command->stat_val);
648 ERROR2("[%s] Cannot execute the command `%s'", command->context->pos, command->context->command_line);
650 unit_set_error(command->unit, command->execlp_errno, 0);
652 command_handle_failure(command, csr_execlp_function_failure);
658 command_check(command_t command)
663 /* we have a signal, store it */
664 if(WIFSIGNALED(command->stat_val))
666 command->signal = strdup(signal_name(WTERMSIG(command->stat_val),command->context->signal));
669 /* we have a signal and no signal is expected */
670 if(WIFSIGNALED(command->stat_val) && !command->context->signal)
673 ERROR3("[%s] `%s' : NOK (unexpected signal `%s' caught)", command->context->pos, command->context->command_line, command->signal);
675 unit_set_error(command->unit, EUNXPSIG, 1);
677 reason = csr_unexpected_signal_caught;
680 /* we have a signal that differ form the expected signal */
681 if(WIFSIGNALED(command->stat_val) && command->context->signal && strcmp(signal_name(WTERMSIG(command->stat_val),command->context->signal),command->context->signal))
684 ERROR4("[%s] `%s' : NOK (got signal `%s' instead of `%s')", command->context->pos, command->context->command_line, command->signal, command->context->signal);
689 unit_set_error(command->unit, ESIGNOTMATCH, 1);
692 reason = csr_signals_dont_match;
695 /* we don't receipt the expected signal */
696 if(!WIFSIGNALED(command->stat_val) && command->context->signal)
699 ERROR3("[%s] `%s' : NOK (expected `%s' not receipt)", command->context->pos, command->context->command_line, command->context->signal);
704 unit_set_error(command->unit, ESIGNOTRECEIPT, 1);
707 reason = csr_expected_signal_not_receipt;
710 /* if the command exit normaly and we expect a exit code : test it */
711 if(WIFEXITED(command->stat_val) /* && INDEFINITE != command->context->exit_code*/)
713 /* the exit codes don't match */
714 if(WEXITSTATUS(command->stat_val) != command->context->exit_code)
716 ERROR4("[%s] %s : NOK (returned code `%d' instead `%d')", command->context->pos, command->context->command_line, WEXITSTATUS(command->stat_val), command->context->exit_code);
721 unit_set_error(command->unit, EEXITCODENOTMATCH, 1);
724 reason = csr_exit_codes_dont_match;
728 /* make sure the reader done */
729 while(!command->reader->done)
730 xbt_os_thread_yield();
733 CloseHandle(command->stdout_fd);
735 close(command->stdout_fd);
738 command->stdout_fd = INDEFINITE_FD;
740 xbt_strbuff_chomp(command->output);
741 xbt_strbuff_chomp(command->context->output);
742 xbt_strbuff_trim(command->output);
743 xbt_strbuff_trim(command->context->output);
747 xbt_dynar_t a = xbt_str_split(command->output->data, "\n");
748 char *out = xbt_str_join(a,"\n||");
750 INFO2("Output of <%s> so far: \n||%s", command->context->pos,out);
753 /* if ouput handling flag is specified check the output */
754 else if(oh_check == command->context->output_handling && command->reader)
756 if(command->output->used != command->context->output->used || strcmp(command->output->data, command->context->output->data))
760 ERROR2("[%s] `%s' : NOK (outputs mismatch):", command->context->pos, command->context->command_line);
764 unit_set_error(command->unit, EOUTPUTNOTMATCH, 1);
768 reason = csr_outputs_dont_match;
770 /* display the diff */
771 diff = xbt_str_diff(command->context->output->data,command->output->data);
776 else if (oh_ignore == command->context->output_handling)
778 INFO1("(ignoring the output of <%s> as requested)",command->context->line);
780 else if (oh_display == command->context->output_handling)
782 xbt_dynar_t a = xbt_str_split(command->output->data, "\n");
783 char *out = xbt_str_join(a,"\n||");
785 INFO3("[%s] Here is the (ignored) command `%s' output: \n||%s",command->context->pos, command->context->command_line, out);
791 xbt_os_mutex_acquire(command->mutex);
793 if(command->status != cs_interrupted)
795 /* signal the success of the command */
796 command->status = cs_successeded;
797 command->successeded = 1;
799 /* increment the number of successeded command of the unit */
800 (command->root->successeded_cmd_nb)++;
803 xbt_os_mutex_release(command->mutex);
807 command_handle_failure(command, reason);
813 command_kill(command_t command)
815 if(INDEFINITE_PID != command->pid)
817 INFO2("[%s] Kill the process `%s'", command->context->pos, command->context->command_line);
818 TerminateProcess(command->pid, INDEFINITE);
823 command_kill(command_t command)
825 if(INDEFINITE_PID != command->pid)
827 kill(command->pid,SIGTERM);
829 if(!command->context->signal)
830 command->context->signal = strdup("SIGTERM");
832 command->exit_code = INDEFINITE;
837 INFO2("[%s] Kill the process `%s'", command->context->pos, command->context->command_line);
838 kill(command->pid,SIGKILL);
846 command_interrupt(command_t command)
848 xbt_os_mutex_acquire(command->mutex);
850 if((command->status != cs_interrupted) && (command->status != cs_failed) && (command->status != cs_successeded))
852 command->status = cs_interrupted;
853 command->reason = csr_interruption_request;
854 command->interrupted = 1;
855 command->unit->interrupted = 1;
857 xbt_os_mutex_acquire(command->root->mutex);
858 (command->root->interrupted_cmd_nb)++;
859 xbt_os_mutex_release(command->root->mutex);
861 if(command->pid != INDEFINITE_PID)
862 command_kill(command);
865 xbt_os_mutex_release(command->mutex);
871 command_summarize(command_t command)
873 if(cs_successeded != command->status)
878 printf(" <killed command>\n");
881 /* display the reason of the status of the command */
882 switch(command->reason)
884 /* the function pipe or CreatePipe() fails */
885 case csr_pipe_function_failed :
886 printf(" reason : pipe() or CreatePipe() function failed (system error)\n");
889 case csr_shell_failed :
890 printf(" reason : shell failed (may be command not found)\n");
893 case csr_get_exit_code_process_function_failure :
894 printf(" reason : ExitCodeProcess() function failed (system error)\n");
897 /* reader failure reasons*/
898 case csr_read_pipe_broken :
899 printf(" reason : command read pipe broken\n");
902 case csr_read_failure :
903 printf(" reason : command stdout read failed\n");
906 /* writer failure reasons */
907 case csr_write_failure :
908 printf(" reason : command stdin write failed\n");
911 case csr_write_pipe_broken :
912 printf(" reason : command write pipe broken\n");
917 printf(" reason : command timeouted\n");
920 /* command failure reason */
921 case csr_command_not_found :
922 printf(" reason : command not found\n");
925 /* context failure reasons */
926 case csr_exit_codes_dont_match :
927 printf(" reason : exit codes don't match\n");
931 /* dup2 function failure reasons */
932 case csr_dup2_function_failure :
933 printf(" reason : dup2() function failed\n");
937 /* execlp function failure reasons */
938 case csr_execlp_function_failure :
939 printf(" reason : execlp() function failed\n");
943 /* waitpid function failure reasons */
944 case csr_waitpid_function_failure :
945 printf(" reason : waitpid() function failed\n");
949 /* CreateProcess function failure reasons */
950 case csr_create_process_function_failure :
951 printf(" reason : CreateProcesss() function failed\n");
955 case csr_outputs_dont_match :
958 printf(" reason : ouputs don't match\n");
959 diff = xbt_str_diff(command->context->output->data,command->output->data);
960 printf(" output diff :\n%s\n",diff);
966 case csr_signals_dont_match :
967 printf(" reason : signals don't match\n");
970 case csr_unexpected_signal_caught:
971 printf(" reason : unexpected signal caught\n");
974 case csr_expected_signal_not_receipt :
975 printf(" reason : expected signal not receipt\n");
978 /* system failure reasons */
979 case csr_fork_function_failure :
980 printf(" reason : fork function failed\n");
983 case csr_wait_failure :
984 printf(" reason : wait command failure\n");
987 /* global/local interruption */
988 case csr_interruption_request :
989 printf(" reason : the command receive a interruption request\n");
994 printf(" reason : unknown \n");
998 if(csr_command_not_found != command->reason && csr_fork_function_failure != command->reason && csr_execlp_function_failure != command->reason)
1000 if(INDEFINITE != command->exit_code)
1001 /* the command exit code */
1002 printf(" exit code : %d\n",command->exit_code);
1004 /* if an expected exit code was specified display it */
1005 if(INDEFINITE != command->context->exit_code)
1006 printf(" expected exit code : %d\n",command->context->exit_code);
1008 printf(" no expected exit code specified\n");
1010 /* if an expected exit code was specified display it */
1011 if(NULL == command->context->signal)
1012 printf(" no expected signal specified\n");
1015 if(NULL != command->signal)
1016 printf(" signal : %s\n",command->signal);
1018 printf(" expected signal : %s\n",command->context->signal);
1021 /* if the command has out put and the metacommand display output is specified display it */
1022 if(command->output && (0 != command->output->used) && (oh_display == command->context->output_handling))
1024 xbt_dynar_t a = xbt_str_split(command->output->data, "\n");
1025 char *out = xbt_str_join(a,"\n||");
1027 printf(" output :\n||%s",out);
1036 command_handle_failure(command_t command, cs_reason_t reason)
1039 unit_t root = command->root;
1041 xbt_os_mutex_acquire(command->mutex);
1043 if((command->status != cs_interrupted) && (command->status != cs_failed))
1045 command->status = cs_failed;
1046 command->reason = reason;
1047 command->failed = 1;
1049 command->unit->failed = 1;
1051 xbt_os_mutex_acquire(root->mutex);
1053 /* increment the number of failed command of the unit */
1054 root->failed_cmd_nb++;
1056 /* if the --ignore-failures option is not specified */
1057 if(!keep_going_unit_flag)
1059 if(!root->interrupted)
1061 /* the unit interrupted (exit for the loop) */
1062 root->interrupted = 1;
1064 /* release the unit */
1065 xbt_os_sem_release(root->sem);
1068 /* if the --keep-going option is not specified */
1069 if(!keep_going_flag)
1073 /* request an global interruption by the runner */
1076 /* release the runner */
1077 xbt_os_sem_release(units_sem);
1082 xbt_os_mutex_release(root->mutex);
1085 xbt_os_mutex_release(command->mutex);
1089 command_free(command_t* ptr)
1091 /* close the stdin and the stdout pipe handles */
1094 if((*ptr)->stdin_fd != INDEFINITE_FD)
1095 CloseHandle((*ptr)->stdin_fd);
1097 if((*ptr)->stdout_fd != INDEFINITE_FD)
1098 CloseHandle((*ptr)->stdout_fd);
1102 if((*ptr)->stdin_fd != INDEFINITE_FD)
1103 close((*ptr)->stdin_fd);
1105 if((*ptr)->stdout_fd != INDEFINITE_FD)
1106 close((*ptr)->stdout_fd);
1111 if(timer_free(&((*ptr)->timer)) < 0)
1117 if(writer_free(&((*ptr)->writer)) < 0)
1123 if(reader_free(&((*ptr)->reader)) < 0)
1128 xbt_strbuff_free((*ptr)->output);
1132 if(context_free(&((*ptr)->context)) < 0)
1137 free((*ptr)->signal);