static pipeline_t va_pipe_pipeline(pipeline_t result_so_far, va_list args) { pipe_processor_t proc = va_arg(args, pipe_processor_t); if(proc == NULL) return result_so_far; void* aux = va_arg(args, void*); size_t pipe_size = va_arg(args, size_t); if(pipe_size == 0) { pipe_consumer_free(result_so_far.out); result_so_far.out = NULL; return result_so_far; } pipe_t* pipe = pipe_new(pipe_size, 0); pipe_connect(result_so_far.out , proc, aux, pipe_producer_new(pipe)); result_so_far.out = pipe_consumer_new(pipe); pipe_free(pipe); return va_pipe_pipeline(result_so_far, args); }
/* 'open' operation of pipe stream. For each pipe stream, it is identified by a decimal number in URI. There could be two types: pipe and pipe.srv. They behave pretty much the same, except they are two ends of the pipe. */ static int pipe_open (PAL_HANDLE *handle, const char * type, const char * uri, int access, int share, int create, int options) { if (!memcmp(type, "pipe:", 5) && !*uri) return pipe_private(handle); char * endptr; PAL_NUM pipeid = strtol(uri, &endptr, 10); PAL_IDX connid = 0; if (*endptr == ':') { if (create & PAL_CREAT_TRY) return -PAL_ERROR_INVAL; connid = strtol(endptr + 1, &endptr, 10); } if (*endptr) return -PAL_ERROR_INVAL; if (!memcmp(type, "pipe.srv:", 9)) return pipe_listen(handle, pipeid, create); if (!memcmp(type, "pipe:", 5)) return pipe_connect(handle, pipeid, connid, create); return -PAL_ERROR_INVAL; }
/* Connect to a server over a full-duplex socket (i.e. created by socketpair), creating the assuan context and returning it in CTX. The server filename is NAME, the argument vector in ARGV. FD_CHILD_LIST is a -1 terminated list of file descriptors not to close in the child. ATFORK is called in the child right after the fork; ATFORKVALUE is passed as the first argument and 0 is passed as the second argument. The ATFORK function should only act if the second value is 0. FLAGS is a bit vector and controls how the function acts: Bit 0: If cleared a simple pipe based server is expected and the function behaves similar to `assuan_pipe_connect'. If set a server based on full-duplex pipes is expected. Such pipes are usually created using the `socketpair' function. It also enables features only available with such servers. Bit 7: If set and there is a need to start the server it will be started as a background process. This flag is useful under W32 systems, so that no new console is created and pops up a console window when starting the server If NAME is NULL, no exec is done but the same process is continued. However all file descriptors are closed and some special environment variables are set. To let the caller detect whether the child or the parent continues, the child returns "client" or "server" in *ARGV (but it is sufficient to check only the first character). This feature is only available on POSIX platforms. */ gpg_error_t assuan_pipe_connect (assuan_context_t ctx, const char *name, const char *argv[], assuan_fd_t *fd_child_list, void (*atfork) (void *opaque, int reserved), void *atforkvalue, unsigned int flags) { TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_pipe_connect", ctx, "name=%s, flags=0x%x", name ? name : "(null)", flags); if (flags & ASSUAN_PIPE_CONNECT_FDPASSING) { #ifdef HAVE_W32_SYSTEM return _assuan_error (ctx, GPG_ERR_NOT_IMPLEMENTED); #else return socketpair_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue); #endif } else return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue, flags); }
pipeline_t pipe_parallel(size_t instances, size_t in_size, pipe_processor_t proc, void* aux, size_t out_size) { pipe_t* in = pipe_new(in_size, 0), * out = pipe_new(out_size, 0); while(instances--) pipe_connect(pipe_consumer_new(in), proc, aux, pipe_producer_new(out)); pipeline_t ret = { .in = pipe_producer_new(in), .out = pipe_consumer_new(out) }; pipe_free(in); pipe_free(out); return ret; }