~emersion/mrsh

469754a5f9b5e75aed11e087f440e058ce073475 — Simon Ser 2 years ago d00afe6
Stop embedding struct process into tasks
M include/shell/job.h => include/shell/job.h +1 -0
@@ 22,6 22,7 @@ struct mrsh_job {
struct mrsh_job *job_create(struct mrsh_state *state, pid_t pgid);
void job_destroy(struct mrsh_job *job);
void job_add_process(struct mrsh_job *job, struct process *proc);
bool job_finished(struct mrsh_job *job);

bool job_init_process(struct mrsh_state *state);
void job_notify(struct mrsh_state *state, pid_t pid, int stat);

M include/shell/process.h => include/shell/process.h +7 -2
@@ 7,6 7,10 @@

/**
 * This struct is used to track child processes.
 *
 * This object is guaranteed to be valid until either:
 * - The process exits
 * - The shell is destroyed
 */
struct process {
	pid_t pid;


@@ 15,9 19,10 @@ struct process {
	int stat;
};

void process_init(struct process *process, struct mrsh_state *state, pid_t pid);
void process_finish(struct process *process);
struct process *process_create(struct mrsh_state *state, pid_t pid);
void process_destroy(struct process *process);
int process_poll(struct process *process);

void process_notify(struct mrsh_state *state, pid_t pid, int stat);

#endif

M include/shell/task_command.h => include/shell/task_command.h +1 -1
@@ 18,7 18,7 @@ struct task_command {
	struct mrsh_array args;

	// if a process
	struct process process;
	struct process *process;

	// if a function
	const struct mrsh_function *fn_def;

M shell/job.c => shell/job.c +14 -15
@@ 118,6 118,10 @@ void job_destroy(struct mrsh_job *job) {
			break;
		}
	}

	for (size_t j = 0; j < job->processes.len; ++j) {
		process_destroy(job->processes.data[j]);
	}
	mrsh_array_finish(&job->processes);
	free(job);
}


@@ 126,21 130,16 @@ void job_add_process(struct mrsh_job *job, struct process *proc) {
	mrsh_array_add(&job->processes, proc);
}

void job_notify(struct mrsh_state *state, pid_t pid, int stat) {
	process_notify(state, pid, stat);

	for (size_t i = 0; i < state->jobs.len; ++i) {
		struct mrsh_job *job = state->jobs.data[i];
		for (ssize_t j = 0; j < (ssize_t)job->processes.len; ++j) {
			struct process *proc = job->processes.data[j];
			if (proc->finished) {
				array_remove(&job->processes, j);
				j -= 1;
			}
		}

		if (job->processes.len == 0) {
			job->finished = true;
bool job_finished(struct mrsh_job *job) {
	for (size_t j = 0; j < job->processes.len; ++j) {
		struct process *proc = job->processes.data[j];
		if (!proc->finished) {
			return false;
		}
	}
	return true;
}

void job_notify(struct mrsh_state *state, pid_t pid, int stat) {
	process_notify(state, pid, stat);
}

M shell/process.c => shell/process.c +13 -15
@@ 1,23 1,17 @@
#include <assert.h>
#include <mrsh/array.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include "shell/process.h"

void process_init(struct process *proc, struct mrsh_state *state, pid_t pid) {
	mrsh_array_add(&state->processes, proc);
struct process *process_create(struct mrsh_state *state, pid_t pid) {
	struct process *proc = calloc(1, sizeof(struct process));
	proc->pid = pid;
	proc->state = state;
	proc->finished = false;
	proc->stat = 0;
}

int process_poll(struct process *proc) {
	if (!proc->finished) {
		return -1;
	}
	return WEXITSTATUS(proc->stat);
	mrsh_array_add(&state->processes, proc);
	return proc;
}

static void array_remove(struct mrsh_array *array, size_t i) {


@@ 26,7 20,7 @@ static void array_remove(struct mrsh_array *array, size_t i) {
	--array->len;
}

static void process_remove(struct process *proc) {
void process_destroy(struct process *proc) {
	struct mrsh_state *state = proc->state;
	for (size_t i = 0; i < state->processes.len; ++i) {
		if (state->processes.data[i] == proc) {


@@ 34,10 28,15 @@ static void process_remove(struct process *proc) {
			break;
		}
	}

	free(proc);
}

void process_finish(struct process *proc) {
	process_remove(proc);
int process_poll(struct process *proc) {
	if (!proc->finished) {
		return -1;
	}
	return WEXITSTATUS(proc->stat);
}

void process_notify(struct mrsh_state *state, pid_t pid, int stat) {


@@ 57,7 56,6 @@ void process_notify(struct mrsh_state *state, pid_t pid, int stat) {
	if (WIFEXITED(stat) || WIFSIGNALED(stat)) {
		proc->finished = true;
		proc->stat = stat;
		process_remove(proc);
	} else {
		assert(false);
	}

M shell/shell.c => shell/shell.c +5 -1
@@ 7,6 7,7 @@
#include <unistd.h>
#include "shell/job.h"
#include "shell/shell.h"
#include "shell/process.h"
#include "shell/task.h"

void mrsh_function_destroy(struct mrsh_function *fn) {


@@ 73,11 74,14 @@ void mrsh_state_finish(struct mrsh_state *state) {
	mrsh_hashtable_for_each(&state->aliases,
		state_string_finish_iterator, NULL);
	mrsh_hashtable_finish(&state->aliases);
	mrsh_array_finish(&state->processes);
	while (state->jobs.len > 0) {
		job_destroy(state->jobs.data[state->jobs.len - 1]);
	}
	mrsh_array_finish(&state->jobs);
	while (state->processes.len > 0) {
		process_destroy(state->processes.data[state->processes.len - 1]);
	}
	mrsh_array_finish(&state->processes);
	struct mrsh_call_frame *args = state->args;
	while (args) {
		struct mrsh_call_frame *prev = args->prev;

M shell/task/async.c => shell/task/async.c +1 -4
@@ 52,16 52,13 @@ static bool task_async_start(struct task *task, struct context *ctx) {
		exit(ret);
	}

	// TODO: this memory is leaked
	struct process *proc = calloc(1, sizeof(struct process));
	process_init(proc, ctx->state, pid);

	pid_t pgid = pid;
	if (setpgid(pid, pgid) != 0) {
		fprintf(stderr, "setpgid failed: %s\n", strerror(errno));
		return false;
	}

	struct process *proc = process_create(ctx->state, pid);
	struct mrsh_job *job = job_create(ctx->state, pgid);
	job_add_process(job, proc);


M shell/task/command.c => shell/task/command.c +0 -3
@@ 14,9 14,6 @@ static void task_command_destroy(struct task *task) {
	mrsh_array_finish(&tc->args);
	switch (tc->type) {
	case TASK_COMMAND_PROCESS:
		if (tc->started) {
			process_finish(&tc->process);
		}
		break;
	case TASK_COMMAND_BUILTIN:
		break;

M shell/task/command_process.c => shell/task/command_process.c +3 -3
@@ 93,8 93,8 @@ static bool task_process_start(struct task_command *tc, struct context *ctx) {

	struct mrsh_job *job = put_into_process_group(ctx, pid);

	process_init(&tc->process, ctx->state, pid);
	job_add_process(job, &tc->process);
	tc->process = process_create(ctx->state, pid);
	job_add_process(job, tc->process);
	return true;
}



@@ 108,5 108,5 @@ int task_process_poll(struct task *task, struct context *ctx) {
		tc->started = true;
	}

	return process_poll(&tc->process);
	return process_poll(tc->process);
}

M shell/task/subshell.c => shell/task/subshell.c +5 -8
@@ 9,15 9,12 @@ struct task_subshell {
	struct task task;
	struct task *subtask;
	bool started;
	struct process process;
	struct process *process;
};

static void task_subshell_destroy(struct task *task) {
	struct task_subshell *ts = (struct task_subshell *)task;
	task_destroy(ts->subtask);
	if (ts->started) {
		process_finish(&ts->process);
	}
	free(ts);
}



@@ 40,10 37,10 @@ static bool task_subshell_start(struct task_subshell *ts, struct context *ctx) {
			exit(ctx->state->exit);
		}
		exit(ret);
	} else {
		process_init(&ts->process, ctx->state, pid);
		return true;
	}

	ts->process = process_create(ctx->state, pid);
	return true;
}

static int task_subshell_poll(struct task *task, struct context *ctx) {


@@ 56,7 53,7 @@ static int task_subshell_poll(struct task *task, struct context *ctx) {
		ts->started = true;
	}

	return process_poll(&ts->process);
	return process_poll(ts->process);
}

static const struct task_interface task_subshell_impl = {

M shell/task/task.c => shell/task/task.c +12 -0
@@ 32,6 32,16 @@ int task_poll(struct task *task, struct context *ctx) {
	return task->status;
}

static void destroy_finished_jobs(struct mrsh_state *state) {
	for (ssize_t i = 0; i < (ssize_t)state->jobs.len; ++i) {
		struct mrsh_job *job = state->jobs.data[i];
		if (job_finished(job)) {
			job_destroy(job);
			--i;
		}
	}
}

int task_run(struct task *task, struct context *ctx) {
	while (true) {
		int ret = task_poll(task, ctx);


@@ 44,6 54,8 @@ int task_run(struct task *task, struct context *ctx) {
			return ret;
		}

		destroy_finished_jobs(ctx->state);

		errno = 0;
		int stat;
		pid_t pid = waitpid(-1, &stat, 0);

M shell/task/word.c => shell/task/word.c +3 -6
@@ 21,7 21,7 @@ struct task_word {

	// only if it's a command
	bool started;
	struct process process;
	struct process *process;
	int fd;
};



@@ 53,9 53,6 @@ static void task_word_swap(struct task_word *tw,

static void task_word_destroy(struct task *task) {
	struct task_word *tw = (struct task_word *)task;
	if (tw->started) {
		process_finish(&tw->process);
	}
	free(tw);
}



@@ 90,7 87,7 @@ static bool task_word_command_start(struct task_word *tw,
	}

	close(fds[1]);
	process_init(&tw->process, ctx->state, pid);
	tw->process = process_create(ctx->state, pid);
	tw->fd = fds[0];
	return true;
}


@@ 196,7 193,7 @@ static int task_word_poll(struct task *task, struct context *ctx) {
			task_word_swap(tw, &ws->word);
		}

		return process_poll(&tw->process);
		return process_poll(tw->process);
	case MRSH_WORD_ARITHMETIC:;
		struct mrsh_word_arithmetic *wa = mrsh_word_get_arithmetic(word);
		char *body_str = mrsh_word_str(wa->body);