static int proc_cleanup_exit(ProcessData *proc_data, uv_process_options_t *proc_opts, int shellopts) { if (proc_data->exited) { if (!emsg_silent && proc_data->exit_status != 0 && !(shellopts & kShellOptSilent)) { MSG_PUTS(_("\nshell returned ")); msg_outnum((int64_t)proc_data->exit_status); msg_putchar('\n'); } } State = proc_data->old_state; if (proc_data->old_mode == TMODE_RAW) { // restore mode settmode(TMODE_RAW); } signal_accept_deadly(); // Release argv memory shell_free_argv(proc_opts->args); return proc_data->exit_status; }
static void close_cb(uv_handle_t *handle) { Job *job = handle_get_job(handle); if (--job->pending_closes == 0) { // Only free the job memory after all the associated handles are properly // closed by libuv rstream_free(job->out); rstream_free(job->err); wstream_free(job->in); shell_free_argv(job->proc_opts.args); free(job->data); free(job); } }
static void close_cb(uv_handle_t *handle) { Job *job = handle_get_job(handle); if (--job->pending_closes == 0) { // Only free the job memory after all the associated handles are properly // closed by libuv rstream_free(job->out); rstream_free(job->err); if (job->in) { wstream_free(job->in); } // Free data memory of process and pipe handles, that was allocated // by handle_set_job in job_start. free(job->proc.data); free(job->proc_stdin.data); free(job->proc_stdout.data); free(job->proc_stderr.data); shell_free_argv(job->proc_opts.args); free(job); } }
static void close_cb(uv_handle_t *handle) { Job *job = handle_get_job(handle); if (handle == (uv_handle_t *)&job->proc) { // Make sure all streams are properly closed to trigger callback invocation // when job->proc is closed close_job_in(job); close_job_out(job); close_job_err(job); } if (--job->refcount == 0) { // Invoke the exit_cb job_exit_callback(job); // Free all memory allocated for the job free(job->proc.data); free(job->proc_stdin.data); free(job->proc_stdout.data); free(job->proc_stderr.data); shell_free_argv(job->proc_opts.args); free(job); } }
/// Tries to start a new job. /// /// @param[out] status The job id if the job started successfully, 0 if the job /// table is full, -1 if the program could not be executed. /// @return The job pointer if the job started successfully, NULL otherwise Job *job_start(JobOptions opts, int *status) { int i; Job *job; // Search for a free slot in the table for (i = 0; i < MAX_RUNNING_JOBS; i++) { if (table[i] == NULL) { break; } } if (i == MAX_RUNNING_JOBS) { // No free slots shell_free_argv(opts.argv); *status = 0; return NULL; } job = xmalloc(sizeof(Job)); // Initialize job->id = i + 1; *status = job->id; job->status = -1; job->refcount = 1; job->stopped_time = 0; job->term_sent = false; job->in = NULL; job->out = NULL; job->err = NULL; job->opts = opts; job->closed = false; process_init(job); if (opts.writable) { handle_set_job((uv_handle_t *)job->proc_stdin, job); job->refcount++; } if (opts.stdout_cb) { handle_set_job((uv_handle_t *)job->proc_stdout, job); job->refcount++; } if (opts.stderr_cb) { handle_set_job((uv_handle_t *)job->proc_stderr, job); job->refcount++; } // Spawn the job if (!process_spawn(job)) { if (opts.writable) { uv_close((uv_handle_t *)job->proc_stdin, close_cb); } if (opts.stdout_cb) { uv_close((uv_handle_t *)job->proc_stdout, close_cb); } if (opts.stderr_cb) { uv_close((uv_handle_t *)job->proc_stderr, close_cb); } process_close(job); event_poll(0); // Manually invoke the close_cb to free the job resources *status = -1; return NULL; } if (opts.writable) { job->in = wstream_new(opts.maxmem); wstream_set_stream(job->in, job->proc_stdin); } // Start the readable streams if (opts.stdout_cb) { job->out = rstream_new(read_cb, rbuffer_new(JOB_BUFFER_SIZE), job); rstream_set_stream(job->out, job->proc_stdout); rstream_start(job->out); } if (opts.stderr_cb) { job->err = rstream_new(read_cb, rbuffer_new(JOB_BUFFER_SIZE), job); rstream_set_stream(job->err, job->proc_stderr); rstream_start(job->err); } // Save the job to the table table[i] = job; return job; }