From: Andre Noll Date: Wed, 26 Jun 2013 18:28:58 +0000 (+0200) Subject: client: Only start stdin task for addblob commands. X-Git-Tag: v0.5.0~10^2 X-Git-Url: http://git.tue.mpg.de/?a=commitdiff_plain;h=72ffa7817c55630c113cc9aa213608ca5518f67c;p=paraslash.git client: Only start stdin task for addblob commands. Currently the command para_client -- ls -lv | grep a fails in a rather strange way, emitting many error messages like grep: writing output: Resource temporarily unavailable This is because O_NONBLOCK is a file status flag rather than a file descriptor flag, i.e. nonblocking mode is a property of the file description rather than the file descriptor. In the above command both stdin of the para_client process and stdout of the grep process refer to the same file description (the terminal). para_client sets stdin to nonblocking mode, hence stdout of the grep process is also in nonblocking mode. We avoid this problem by changing client.c to only set stdin to nonblocking mode if we actually need to read from stdin, i.e. only for the addblob commands. This is achieved by registering the stdin task (which sets the O_NONBLOCK flag) only if the client status is CL_SENDING. For addblob commands the client status changes from CL_EXECUTING to CL_SENDING, so we can not simply terminate the supervisor task any more after the stdout task has been registered. Instead we must keep this task alive and (a) remember that stdout has already been started, and (b) start the stdin task in case the client status becomes CL_SENDING. Unfortunately, there is no simple way to store this bit of information as we don't have a dedicated supervisor structure yet. Therefore this patch introduces this structure as a task struct plus a single boolean. --- diff --git a/client.c b/client.c index 413d08cc..44862ab9 100644 --- a/client.c +++ b/client.c @@ -531,25 +531,39 @@ __noreturn static void print_completions(void) #endif /* HAVE_READLINE */ +struct supervisor_task { + bool stdout_task_started; + struct task task; +}; + static void supervisor_post_select(struct sched *s, struct task *t) { + struct supervisor_task *svt = container_of(t, struct supervisor_task, + task); + if (ct->task.error < 0) { t->error = ct->task.error; return; } - if (ct->status == CL_EXECUTING) { - stdin_set_defaults(&sit); - register_task(s, &sit.task); + if (!svt->stdout_task_started && ct->status == CL_EXECUTING) { stdout_set_defaults(&sot); register_task(s, &sot.task); + svt->stdout_task_started = true; + return; + } + if (ct->status == CL_SENDING) { + stdin_set_defaults(&sit); + register_task(s, &sit.task); t->error = -E_TASK_STARTED; return; } } -static struct task svt = { - .post_select = supervisor_post_select, - .status = "supervisor task" +static struct supervisor_task supervisor_task = { + .task = { + .post_select = supervisor_post_select, + .status = "supervisor task" + } }; /** @@ -598,7 +612,7 @@ int main(int argc, char *argv[]) goto out; sot.btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "stdout", .parent = ct->btrn[0])); - register_task(&sched, &svt); + register_task(&sched, &supervisor_task.task); ret = schedule(&sched); if (ret >= 0 && ct->task.error < 0) { switch(ct->task.error) {