aboutsummaryrefslogtreecommitdiffstats
path: root/main/czmq
diff options
context:
space:
mode:
authorTuan Hoang <tmhoang@linux.vnet.ibm.com>2019-01-29 14:08:13 +0100
committerNatanael Copa <ncopa@alpinelinux.org>2019-03-22 15:59:14 +0000
commitfd5c3e8fc14612619e0a2377b61d041bc1648661 (patch)
treebf21398f3eea1dd30bffe1fed8b2f44554e75f57 /main/czmq
parent4cb8975d681d58e58724e0354b101cbc2a0e7dbb (diff)
downloadaports-fd5c3e8fc14612619e0a2377b61d041bc1648661.tar.bz2
aports-fd5c3e8fc14612619e0a2377b61d041bc1648661.tar.xz
main/czmq: backport from master to fix tests on s390x
zproc/zsp tests seem to be fixed in master zdigest and SHA1 functions fail when building with CMake Use normal/official build scripts instead
Diffstat (limited to 'main/czmq')
-rw-r--r--main/czmq/APKBUILD31
-rw-r--r--main/czmq/zproc_zsp.patch768
2 files changed, 786 insertions, 13 deletions
diff --git a/main/czmq/APKBUILD b/main/czmq/APKBUILD
index e4afa86266..2b018f8bca 100644
--- a/main/czmq/APKBUILD
+++ b/main/czmq/APKBUILD
@@ -2,31 +2,35 @@
# Maintainer: Jakub Jirutka <jakub@jirutka.cz>
pkgname=czmq
pkgver=4.1.1
-pkgrel=0
+pkgrel=1
pkgdesc="High-level C binding for ZeroMQ"
url="http://czmq.zeromq.org/"
-arch="all !s390x" # zproxy test timeouts on s390x
+arch="all"
license="MPL-2.0"
depends_dev="util-linux-dev zeromq-dev"
-makedepends="$depends_dev cmake"
+makedepends="$depends_dev libtool autoconf automake"
subpackages="$pkgname-dev"
-source="$pkgname-$pkgver.tar.gz::https://github.com/zeromq/$pkgname/archive/v$pkgver.tar.gz"
+source="$pkgname-$pkgver.tar.gz::https://github.com/zeromq/$pkgname/archive/v$pkgver.tar.gz
+ zproc_zsp.patch
+ "
builddir="$srcdir/$pkgname-$pkgver"
+prepare() {
+ default_prepare
+ cd "$builddir"
+ ./autogen.sh
+}
build() {
cd "$builddir"
-
- # Note: One test segfaults when built with MinSizeRel (-Os).
- cmake \
- -DCMAKE_BUILD_TYPE=Release \
- -DCMAKE_INSTALL_PREFIX=/usr \
- -DCMAKE_VERBOSE_MAKEFILE=ON
- make
+ ./configure \
+ --prefix=/usr \
+ --with-libsystemd=no
+ make -j1
}
check() {
cd "$builddir"
- make test
+ make -j1 check
}
package() {
@@ -34,4 +38,5 @@ package() {
make install DESTDIR="$pkgdir"
}
-sha512sums="c36d509e154a2142154f339294375bab0f6a2752f025a4489067bbddb22c4ef8f8e501797e755ac3779aa5c1c19397d32f7195ba80ae6b81e349f22c7634fb91 czmq-4.1.1.tar.gz"
+sha512sums="c36d509e154a2142154f339294375bab0f6a2752f025a4489067bbddb22c4ef8f8e501797e755ac3779aa5c1c19397d32f7195ba80ae6b81e349f22c7634fb91 czmq-4.1.1.tar.gz
+647c4915220f8e668750495b7511b60e8cf67b677de920176905797d76ed6fad7b63c5cc930a6635f77fb9c0c28427f7c6662df5de18e91412c3c76dde43e6a9 zproc_zsp.patch"
diff --git a/main/czmq/zproc_zsp.patch b/main/czmq/zproc_zsp.patch
new file mode 100644
index 0000000000..00ddc06311
--- /dev/null
+++ b/main/czmq/zproc_zsp.patch
@@ -0,0 +1,768 @@
+Backport from git master at:
+1a6a8b1f50610e59bd12b63f7dc409f8c11ee79a
+
+
+diff --git a/include/zproc.h b/include/zproc.h
+index 6762d72..7e13420 100644
+--- a/include/zproc.h
++++ b/include/zproc.h
+@@ -122,12 +122,19 @@ CZMQ_EXPORT bool
+ zproc_running (zproc_t *self);
+
+ // *** Draft method, for development use, may change without warning ***
++// The timeout should be zero or greater, or -1 to wait indefinitely.
+ // wait or poll process status, return return code
+ CZMQ_EXPORT int
+- zproc_wait (zproc_t *self, bool hang);
++ zproc_wait (zproc_t *self, int timeout);
+
+ // *** Draft method, for development use, may change without warning ***
+-// return internal actor, usefull for the polling if process died
++// send SIGTERM signal to the subprocess, wait for grace period and
++// eventually send SIGKILL
++CZMQ_EXPORT void
++ zproc_shutdown (zproc_t *self, int timeout);
++
++// *** Draft method, for development use, may change without warning ***
++// return internal actor, useful for the polling if process died
+ CZMQ_EXPORT void *
+ zproc_actor (zproc_t *self);
+
+diff --git a/src/zproc.c b/src/zproc.c
+index a65c6e6..305c4a8 100644
+--- a/src/zproc.c
++++ b/src/zproc.c
+@@ -95,9 +95,11 @@ struct _zpair_t {
+ };
+
+ static zpair_t*
+-zpair_new (char* endpoint) {
++zpair_new (char *endpoint) {
+ zpair_t *self = (zpair_t*) zmalloc (sizeof (zpair_t));
+- self->endpoint = endpoint;
++ if (self) {
++ self->endpoint = endpoint;
++ }
+ return self;
+ }
+
+@@ -213,7 +215,6 @@ struct _zproc_t {
+ int stdoutpipe [2]; // stdout pipe
+ int stderrpipe [2]; // stderr pipe
+
+- zpair_t *execpair; // pair used to synchronize zproc_run with actor
+ zpair_t *stdinpair; // stdin socketpair
+ zpair_t *stdoutpair; // stdout socketpair
+ zpair_t *stderrpair; // stderr socketpair
+@@ -237,6 +238,7 @@ zproc_new ()
+ }
+
+ zproc_t *self = (zproc_t*) zmalloc (sizeof (zproc_t));
++ assert (self);
+ self->verbose = false;
+
+ self->stdinpipe [0] = -1;
+@@ -247,19 +249,19 @@ zproc_new ()
+ self->stderrpipe [1] = -1;
+
+ zuuid_t *uuid = zuuid_new ();
+- self->execpair = zpair_new (
+- zsys_sprintf ("#inproc://zproc-%s-exec", zuuid_str_canonical (uuid))
+- );
+- zpair_mkpair (self->execpair);
++ assert (uuid);
+ self->stdinpair = zpair_new (
+ zsys_sprintf ("#inproc://zproc-%s-stdin", zuuid_str_canonical (uuid))
+ );
++ assert (self->stdinpair);
+ self->stdoutpair = zpair_new (
+ zsys_sprintf ("#inproc://zproc-%s-stdout", zuuid_str_canonical (uuid))
+ );
++ assert (self->stdoutpair);
+ self->stderrpair = zpair_new (
+ zsys_sprintf ("#inproc://zproc-%s-stderr", zuuid_str_canonical (uuid))
+ );
++ assert (self->stderrpair);
+ zuuid_destroy (&uuid);
+
+ return self;
+@@ -271,23 +273,16 @@ zproc_destroy (zproc_t **self_p) {
+ assert (self_p);
+ if (*self_p) {
+ zproc_t *self = *self_p;
+- zproc_wait (self, true);
++ zproc_shutdown (self, 5000);
+ zactor_destroy (&self->actor);
+
+- if (self->stdinpipe [0] != -1) {
+- close (self->stdinpipe [0]);
+- close (self->stdinpipe [1]);
+- }
+- if (self->stdoutpipe [0] != -1) {
+- close (self->stdoutpipe [0]);
+- close (self->stdoutpipe [1]);
+- }
+- if (self->stderrpipe [0] != -1) {
+- close (self->stderrpipe [0]);
+- close (self->stderrpipe [1]);
+- }
++ if (self->stdinpipe [0] != -1) close (self->stdinpipe [0]);
++ if (self->stdinpipe [1] != -1) close (self->stdinpipe [1]);
++ if (self->stdoutpipe [0] != -1) close (self->stdoutpipe [0]);
++ if (self->stdoutpipe [1] != -1) close (self->stdoutpipe [1]);
++ if (self->stderrpipe [0] != -1) close (self->stderrpipe [0]);
++ if (self->stderrpipe [1] != -1) close (self->stderrpipe [1]);
+
+- zpair_destroy (&self->execpair);
+ zpair_destroy (&self->stdinpair);
+ zpair_destroy (&self->stdoutpair);
+ zpair_destroy (&self->stderrpair);
+@@ -430,7 +425,7 @@ int
+ zproc_returncode (zproc_t *self) {
+ assert (self);
+ assert (zproc_pid(self));
+- zproc_wait (self, false);
++ zproc_wait (self, 0);
+ return self->return_code;
+ }
+
+@@ -456,74 +451,118 @@ s_fd_in_handler (zloop_t *self, zmq_pollitem_t *item, void *socket)
+ byte buf [BUF_SIZE];
+ ssize_t r = 1;
+
+- while (r > 0) {
+- memset (buf, '\0', BUF_SIZE);
+- r = read (item->fd, buf, BUF_SIZE);
+- if (r == -1) {
+- zsys_error ("read from fd %d: %s", item->fd, strerror (errno));
+- break;
+- }
+- else
+- if (r == 0)
+- break;
+- zframe_t *frame = zframe_new (buf, r);
+- zsock_bsend (socket, "f", frame, NULL);
+- zframe_destroy (&frame);
++ memset (buf, '\0', BUF_SIZE);
++ r = read (item->fd, buf, BUF_SIZE);
++ if (r == -1) {
++ zsys_warning ("read from fd %d: %s", item->fd, strerror (errno));
++ return 0;
+ }
++ else
++ if (r == 0)
++ return 0;
++ zframe_t *frame = zframe_new (buf, r);
++ zsock_bsend (socket, "f", frame, NULL);
++ zframe_destroy (&frame);
+ return 0;
+ #undef BUF_SIZE
+ }
+
+ static int
+-s_fd_out_handler (zloop_t *self, zmq_pollitem_t *item, void *socket)
++s_fd_out_handler (zloop_t *self, zsock_t *socket, void *fd_p)
+ {
++ assert (self);
++ assert (socket);
++ assert (fd_p);
+ ssize_t r = 1;
++ int fd = *(int*)fd_p;
+
+- while (r > 0) {
+-
+- zframe_t *frame;
+- r = zsock_brecv (socket, "f", &frame);
+- if (r == -1) {
+- zsys_error ("read from socket <%p>: %s", socket, strerror (errno));
+- break;
+- }
+-
+- r = write (item->fd, zframe_data (frame), zframe_size (frame));
++ zframe_t *frame;
++ r = zsock_brecv (socket, "f", &frame);
++ if (r == -1) {
+ zframe_destroy (&frame);
++ zsys_error ("read from socket <%p>: %s", socket, strerror (errno));
++ return -1;
++ }
+
+- if (r == -1) {
+- zsys_error ("write to fd %d: %s", item->fd, strerror (errno));
+- break;
+- }
++ r = write (fd, zframe_data (frame), zframe_size (frame));
++ zframe_destroy (&frame);
++
++ if (r == -1) {
++ zsys_error ("write to fd %d: %s", fd, strerror (errno));
++ return -1;
+ }
+ return 0;
+ }
+
++// connect pipe (fd) with zeromq socket, so when data are signaled on `fd`, they are forwarded to `socket`
++// used for readable ends of pipesm like stdout/stderr
+ static int
+-s_zproc_addfd (zproc_t *self, int fd, void* socket, int flags) {
++s_zproc_readfd (zproc_t *self, int fd, void* socket) {
+ assert (self);
+ #if defined (__WINDOWS__)
+- zsys_error ("s_zproc_addfd not implemented for Windows");
++ zsys_error ("s_zproc_readfd not implemented for Windows");
+ return -1;
+ #else
+- zmq_pollitem_t it = {NULL, fd, flags, 0};
++ assert (socket);
++ assert (zsock_is (socket));
++ zmq_pollitem_t it = {NULL, fd, ZMQ_POLLIN, 0};
+ return zloop_poller (
+ self->loop_ref,
+ &it,
+- flags == ZMQ_POLLIN ? s_fd_in_handler : s_fd_out_handler,
++ s_fd_in_handler,
+ socket);
+ #endif
+ }
+
++// connect zeromq `socket` with writable end of pipe. When data are signaled on `fd`, they are forwarded to `fd`
++// used for writable ends of pipes like stdin
++static int
++s_zproc_readsocket (zproc_t *self, int* fd_p, void* socket) {
++ assert (self);
++#if defined (__WINDOWS__)
++ zsys_error ("s_zproc_readfd not implemented for Windows");
++ return -1;
++#else
++ assert (socket);
++ assert (zsock_is (socket));
++ return zloop_reader (
++ self->loop_ref,
++ (zsock_t*)socket,
++ s_fd_out_handler,
++ (void*)fd_p);
++#endif
++}
++
++
+ static int
+ s_zproc_alive (zloop_t *loop, int timer_id, void *args)
+ {
+ zproc_t *self = (zproc_t*) args;
+- if (zsys_interrupted)
+- return -1;
+- if (zproc_pid (self) && zproc_running (self))
++ if (! zproc_running (self))
+ return 0;
+- return -1;
++#if defined (__WINDOWS__)
++ if (zproc_running (self))
++ return 0;
++#else
++ int status;
++ int r = waitpid (self->pid, &status, WNOHANG);
++ if (r > 0) {
++ if (WIFEXITED(status)) {
++ self->return_code = WEXITSTATUS(status);
++ if (self->verbose)
++ zsys_debug ("zproc_wait [%d]:\tWIFEXITED, self->return_code=%d", self->pid, self->return_code);
++ self->running = false;
++ }
++ else if (WIFSIGNALED(status)) {
++ self->return_code = - WTERMSIG(status);
++ if (self->verbose)
++ zsys_debug ("zproc_wait [%d]:\tWIFSIGNALED, self->return_code=%d", self->pid, self->return_code);
++ self->running = false;
++ }
++ return -1;
++ }
++ return 0;
++#endif
+ }
+
+ static int
+@@ -546,7 +585,6 @@ s_zproc_execve (zproc_t *self)
+ zsys_debug ("zproc: command to start: %s", commandline);
+
+ siStartInfo.cb = sizeof (siStartInfo);
+- zsock_signal (zpair_write (self->execpair), 0);
+ self->running = CreateProcessA(
+ NULL, // app name
+ commandline, // command line
+@@ -576,17 +614,20 @@ s_zproc_execve (zproc_t *self)
+ fcntl (self->stdinpipe [0], F_SETFL, n_flags);
+ dup2 (self->stdinpipe [0], STDIN_FILENO);
+ close (self->stdinpipe [1]);
++ self->stdinpipe[1] = -1;
+ }
+
+ // redirect stdout if set_stdout was called
+ if (self->stdoutpipe [0] != -1) {
+ close (self->stdoutpipe [0]);
++ self->stdoutpipe [0] = -1;
+ dup2 (self->stdoutpipe [1], STDOUT_FILENO);
+ }
+
+ // redirect stderr if set_stderr was called
+ if (self->stderrpipe [0] != -1) {
+ close (self->stderrpipe [0]);
++ self->stderrpipe [0] = -1;
+ dup2 (self->stderrpipe [1], STDERR_FILENO);
+ }
+
+@@ -621,7 +662,6 @@ s_zproc_execve (zproc_t *self)
+ else
+ env = environ;
+
+- zsock_signal (zpair_write (self->execpair), 0);
+ r = execve (filename, argv2, env);
+ if (r == -1) {
+ zsys_error ("fail to run %s: %s", filename, strerror (errno));
+@@ -643,19 +683,22 @@ s_zproc_execve (zproc_t *self)
+ zsys_debug ("process %s with pid %d started", filename, self->pid);
+
+ if (self->stdinpipe [0] != -1) {
+- s_zproc_addfd (self, self->stdinpipe [1], zpair_read (self->stdinpair), ZMQ_POLLOUT);
++ s_zproc_readsocket (self, self->stdinpipe+1, zpair_read (self->stdinpair));
+ close (self->stdinpipe [0]);
++ self->stdinpipe [0] = -1;
+ }
+
+ // add a handler for read end of stdout
+ if (self->stdoutpipe [1] != -1) {
+- s_zproc_addfd (self, self->stdoutpipe [0], zpair_write (self->stdoutpair), ZMQ_POLLIN);
++ s_zproc_readfd (self, self->stdoutpipe [0], zpair_write (self->stdoutpair));
+ close (self->stdoutpipe[1]);
++ self->stdoutpipe [1] = -1;
+ }
+ // add a handler for read end of stderr
+ if (self->stderrpipe [1] != -1) {
+- s_zproc_addfd (self, self->stderrpipe [0], zpair_write (self->stderrpair), ZMQ_POLLIN);
++ s_zproc_readfd (self, self->stderrpipe [0], zpair_write (self->stderrpair));
+ close (self->stderrpipe[1]);
++ self->stderrpipe [1] = -1;
+ }
+ }
+
+@@ -685,7 +728,7 @@ s_pipe_handler (zloop_t *loop, zsock_t *pipe, void *args) {
+ }
+
+ s_zproc_execve (self);
+- zsock_wait (self->execpair);
++ zclock_sleep (10); // magic sleep, give execve a bit of time
+ zsock_signal (pipe, 0);
+ }
+
+@@ -703,6 +746,7 @@ s_zproc_actor (zsock_t *pipe, void *args)
+ zproc_t *self = (zproc_t*) args;
+ zloop_t *loop = zloop_new ();
+ assert (loop);
++ // zloop_set_verbose (loop, self->verbose);
+ self->loop_ref = loop;
+ self->pipe = pipe;
+
+@@ -712,6 +756,10 @@ s_zproc_actor (zsock_t *pipe, void *args)
+ zsock_signal (pipe, 0);
+ zloop_start (loop);
+ zloop_destroy (&loop);
++ while (zproc_running (self)) {
++ zclock_sleep (500);
++ s_zproc_alive (NULL, -1, self);
++ }
+ zsock_signal (pipe, 0);
+ }
+
+@@ -722,7 +770,14 @@ zproc_run (zproc_t *self)
+ assert (!self->actor);
+
+ if (!self->args || zlist_size (self->args) == 0) {
+- zsys_error ("No arguments, nothing to run. Call zproc_set_args before");
++ if (self->verbose)
++ zsys_error ("zproc: No arguments, nothing to run. Call zproc_set_args before");
++ return -1;
++ }
++ const char *filename = (const char*) zlist_first (self->args);
++ if (!zfile_exists (filename)) {
++ if (self->verbose)
++ zsys_error ("zproc: '%s' does not exists", filename);
+ return -1;
+ }
+
+@@ -736,7 +791,7 @@ zproc_run (zproc_t *self)
+ }
+
+ int
+-zproc_wait (zproc_t *self, bool wait) {
++zproc_wait (zproc_t *self, int timeout) {
+ #if defined (__WINDOWS__)
+ if (!self->running) {
+ if (self->verbose)
+@@ -744,10 +799,10 @@ zproc_wait (zproc_t *self, bool wait) {
+ return self->return_code;
+ }
+
+- uint32_t r = WaitForSingleObject (self->piProcInfo.hProcess, wait ? INFINITE : 0);
++ uint32_t r = WaitForSingleObject (self->piProcInfo.hProcess, timeout == -1 ? INFINITE : timeout);
+ if (self->verbose)
+ zsys_debug ("zproc_wait [%d]:\twaitforsingleobject, r=%d", zproc_pid (self), r);
+- if (!wait && r == 0x00000102) {
++ if (timeout >= 0 && r == 0x00000102) {
+ // still running
+ return self->return_code;
+ }
+@@ -764,13 +819,12 @@ zproc_wait (zproc_t *self, bool wait) {
+ return -1;
+ #else
+ assert (self);
++
+ if (!self->pid)
+ return 0;
+
+ if (self->verbose)
+- zsys_debug ("zproc_wait [%d]: wait=%s", self->pid, wait ? "true" : "false");
+- int status = -1;
+- int options = !wait ? WNOHANG : 0;
++ zsys_debug ("zproc_wait [%d]: timeout=%d", self->pid, timeout);
+ if (self->verbose)
+ zsys_debug ("zproc_wait [%d]:\t!self->running=%s", self->pid, self->running ? "true" : "false");
+ if (!self->running)
+@@ -778,43 +832,36 @@ zproc_wait (zproc_t *self, bool wait) {
+
+ if (self->verbose)
+ zsys_debug ("zproc_wait [%d]:\twaitpid", self->pid);
+- int r = waitpid (self->pid, &status, options);
+- if (self->verbose)
+- zsys_debug ("zproc_wait [%d]:\twaitpid, r=%d", self->pid, r);
+- if (!wait && r == 0)
+- return self->return_code;
+
+- if (WIFEXITED(status)) {
+- self->running = false;
+- self->return_code = WEXITSTATUS(status);
+- if (self->verbose)
+- zsys_debug ("zproc_wait [%d]:\tWIFEXITED, self->return_code=%d", self->pid, self->return_code);
++ if (timeout < 0) {
++ // infinite wait
++ while (zproc_running (self))
++ zclock_sleep (200);
+ return self->return_code;
+ }
+- else if (WIFSIGNALED(status)) {
+- self->running = false;
+- self->return_code = - WTERMSIG(status);
+- if (self->verbose)
+- zsys_debug ("zproc_wait [%d]:\tWIFSIGNALED, self->return_code=%d", self->pid, self->return_code);
++ else if (timeout == 0) {
++ // just check and continue
+ return self->return_code;
+-
+- /*
+- if (WCOREDUMP(status)) {
+- self->core_dumped = true;
++ } else {
++ // wait up to timeout
++ int quit = zclock_mono () + timeout;
++ while (true) {
++ if (! zproc_running (self))
++ break;
++ if (zclock_mono () >= quit)
++ break;
++ zclock_sleep (200);
+ }
+- */
++ return self->return_code;
+ }
+- if (self->verbose)
+- zsys_debug ("zproc_wait [%d]: self->return_code=%d", self->pid, self->return_code);
+- return ZPROC_RUNNING;
+ #endif
+ }
+
+ bool
+ zproc_running (zproc_t *self) {
+ assert (self);
+- assert (zproc_pid (self));
+- return zproc_wait (self, false) == ZPROC_RUNNING;
++ if (! zproc_pid (self)) return false;
++ return zproc_wait (self, 0) == ZPROC_RUNNING;
+ }
+
+ void *
+@@ -832,17 +879,34 @@ zproc_kill (zproc_t *self, int signum) {
+ if (signum == SIGTERM) {
+ if (! TerminateProcess (self->piProcInfo.hProcess, 255))
+ zsys_error ("zproc_kill [%d]:\tTerminateProcess failed", zproc_pid (self));
+- zproc_wait (self, false);
++ zproc_wait (self, 0);
+ } else {
+ zsys_error ("zproc_kill: [%d]:\tOnly SIGTERM is implemented on windows", zproc_pid (self));
+ }
+ }
+ #else
+- if (zproc_pid (self) > 0) {
++ if (zproc_running (self)) {
+ int r = kill (self->pid, signum);
+ if (r != 0)
+ zsys_error ("kill of pid=%d failed: %s", self->pid, strerror (errno));
+- zproc_wait (self, false);
++ zproc_wait (self, 0);
++ }
++#endif
++}
++
++// send SIGTERM signal to the subprocess, wait for grace period and KILL
++void
++zproc_shutdown (zproc_t *self, int timeout)
++{
++ assert (self);
++ if (timeout < 0) timeout = 0;
++
++ zproc_kill (self, SIGTERM);
++ zproc_wait (self, timeout);
++#if ! defined (__WINDOWS__)
++ if (zproc_running (self)) {
++ zproc_kill (self, SIGKILL);
++ zproc_wait (self, timeout);
+ }
+ #endif
+ }
+@@ -960,6 +1024,7 @@ zproc_test (bool verbose)
+ printf ("OK\n");
+ return;
+ #endif
++ {
+ // Test case #1: run command, wait until it ends and get the (stdandard) output
+ zproc_t *self = zproc_new ();
+ assert (self);
+@@ -986,15 +1051,103 @@ zproc_test (bool verbose)
+ if (verbose)
+ zframe_print (frame, "1:");
+ zframe_destroy (&frame);
+- r = zproc_wait (self, true);
++ r = zproc_wait (self, -1);
+ assert (r == 0);
+ zproc_destroy (&self);
++ }
+
+- // Test case #2: use never ending subprocess and poller to read data from it
+- // Create new zproc instance
+- self = zproc_new ();
++ {
++ // Test case#2: run zsp helper with a content written on stdin, check if it was passed to stdout
++ zproc_t *self = zproc_new ();
++ assert (self);
++ zproc_set_verbose (self, verbose);
++ // forward input from stdin to stderr
++ zproc_set_argsx (self, file, "--stdin", "--stderr", NULL);
++ // FIXME: there is a BUG in zproc somewhere, you can't gen an output from both stdout/stderr
++ //zproc_set_argsx (self, file, "--stdin", "--stdout", "--stderr", NULL);
++ zproc_set_stdin (self, NULL);
++ // FIXME: the bug
++ //zproc_set_stdout (self, NULL);
++ zproc_set_stderr (self, NULL);
++
++ // send data to stdin
++ int r = zproc_run (self);
++ assert (r == 0);
++ zframe_t *frame = zframe_new ("Lorem ipsum\0\0", strlen ("Lorem ipsum")+2);
++ assert (frame);
++ zsock_bsend (zproc_stdin (self), "f", frame);
++ zframe_destroy (&frame);
++
++ // FIXME: the bug
++ //zproc_set_stdout (self, NULL);
++ // read data from stdout
++ /*
++ zsys_debug ("BAF1");
++ zsock_brecv (zproc_stdout (self), "f", &frame);
++ zsys_debug ("BAF2");
++ assert (frame);
++ assert (zframe_data (frame));
++ if (verbose)
++ zframe_print (frame, "2.stdout:");
++ assert (!strncmp ((char*) zframe_data (frame), "Lorem ipsum", 11));
++ */
++
++ // read data from stderr
++ zsock_brecv (zproc_stderr (self), "f", &frame);
++ assert (frame);
++ assert (zframe_data (frame));
++ if (verbose)
++ zframe_print (frame, "2.stderr:");
++ assert (!strncmp ((char*) zframe_data (frame), "Lorem ipsum", 11));
++ zproc_kill (self, SIGTERM);
++ zproc_wait (self, -1);
++ zframe_destroy (&frame);
++ zproc_destroy (&self);
++ }
++
++ {
++ // Test case#3: run non existing binary
++ zproc_t *self = zproc_new ();
++ assert (self);
+ zproc_set_verbose (self, verbose);
++ // forward input from stdin to stderr
++ zproc_set_argsx (self, "/not/existing/file", NULL);
++
++ int r = zproc_run (self);
++ assert (r == -1);
++ zproc_destroy (&self);
++ }
++
++ {
++ // Test case #4: child abort itself
++ zproc_t *self = zproc_new ();
+ assert (self);
++ zproc_set_verbose (self, verbose);
++ zproc_set_argsx (self, file, "--verbose", "--abrt", NULL);
++ zproc_set_stdout (self, NULL);
++ zproc_set_stderr (self, NULL);
++ zproc_set_stdin (self, NULL);
++
++ int r = zproc_run (self);
++ zclock_sleep (100); // to let actor start the process
++ assert (r != -1);
++ zclock_sleep (100);
++ zframe_t *frame;
++ zsock_brecv (zproc_stdout (self), "f", &frame);
++ assert (zframe_is (frame));
++ assert (zframe_size (frame) > 0);
++ zframe_destroy (&frame);
++ zproc_wait (self, -1);
++ assert (zproc_returncode (self) == -SIGABRT);
++ zproc_destroy (&self);
++ }
++
++ {
++ // Test case #5: use never ending subprocess and poller to read data from it
++ // Create new zproc instance
++ zproc_t *self = zproc_new ();
++ assert (self);
++ zproc_set_verbose (self, verbose);
+ // join stdout of the process to zeromq socket
+ // all data will be readable from zproc_stdout socket
+ zproc_set_stdout (self, NULL);
+@@ -1025,7 +1178,7 @@ zproc_test (bool verbose)
+ zsys_debug("zproc_test() : sleeping 4000 msec to gather some output from helper");
+ zclock_sleep (4000);
+ zproc_kill (self, SIGTERM);
+- zproc_wait (self, true);
++ zproc_wait (self, -1);
+
+ // read the content from zproc_stdout - use zpoller and a loop
+ bool stdout_read = false;
+@@ -1089,6 +1242,47 @@ zproc_test (bool verbose)
+ assert (stdout_read);
+ zpoller_destroy (&poller);
+ zproc_destroy (&self);
++ }
++ {
++ // testcase #6 wait for process that hangs, kill it
++ zproc_t *self = zproc_new ();
++ assert (self);
++ zproc_set_verbose (self, verbose);
++
++ zproc_set_argsx (self, file, NULL);
++
++ if (verbose)
++ zsys_debug("zproc_test() : launching helper '%s'", file);
++
++ int r = zproc_run (self);
++ assert (r == 0);
++ r = zproc_wait (self, 1000);
++ assert (r == ZPROC_RUNNING);
++ assert (zproc_running (self));
++ zproc_shutdown (self, 1000);
++ assert (!zproc_running (self));
++ zproc_destroy (&self);
++ }
++ {
++ // testcase #7 wait for process that exits earlier
++ zproc_t *self = zproc_new ();
++ assert (self);
++ zproc_set_verbose (self, verbose);
++
++ zproc_set_argsx (self, file, "--quit", "1", NULL);
++
++ if (verbose)
++ zsys_debug("zproc_test() : launching helper '%s' --quit 1", file);
++
++ int r = zproc_run (self);
++ assert (r == 0);
++ int t = zclock_mono ();
++ r = zproc_wait (self, 8000);
++ assert (r == 0);
++ t = zclock_mono () - t;
++ assert (t < 2000);
++ zproc_destroy (&self);
++ }
+ // @end
+
+ // to have zpair print and arr print methods
+diff --git a/src/zsp.c b/src/zsp.c
+index 67a499f..ba57beb 100644
+--- a/src/zsp.c
++++ b/src/zsp.c
+@@ -29,6 +29,8 @@ int main (int argc, char *argv [])
+ bool use_stdin = false;
+ bool use_stderr = false;
+ bool use_stdout = false;
++ bool abrt = false;
++ int quit = 0;
+
+ char *message = NULL;
+
+@@ -41,7 +43,9 @@ int main (int argc, char *argv [])
+ #endif
+ puts (" --stderr / -e output on stderr");
+ puts (" --stdout / -o output on stdout");
++ puts (" --abrt / -a crash with SIGABRT on start");
+ puts (" --verbose / -v verbose mode");
++ puts (" --quit / -q X quit after X seconds");
+ puts (" --help / -h this information");
+ return 0;
+ }
+@@ -62,6 +66,16 @@ int main (int argc, char *argv [])
+ || streq (argv [argn], "-v"))
+ verbose = true;
+ else
++ if (streq (argv [argn], "--abrt")
++ || streq (argv [argn], "-a"))
++ abrt = true;
++ else
++ if (streq (argv [argn], "--quit")
++ || streq (argv [argn], "-q")) {
++ quit = atoi (argv [argn + 1]) * 1000;
++ ++argn;
++ }
++ else
+ if (argv [argn][0] == '-') {
+ printf ("Unknown option: %s\n", argv [argn]);
+ return 1;
+@@ -87,7 +101,18 @@ int main (int argc, char *argv [])
+ assert (r == 0);
+ }
+
++ if (abrt) {
++ if (verbose)
++ zsys_info ("Going to abort myself");
++#if defined (__WINDOWS__)
++ assert (false); // TODO: how to do kill myelf on Windows?
++#else
++ kill (getpid (), SIGABRT);
++#endif
++ }
++
+ // Insert main code here
++ int64_t start = zclock_mono ();
+ while (!zsys_interrupted) {
+ #if ! defined (__WINDOWS__)
+ if (use_stdin) {
+@@ -110,6 +135,7 @@ int main (int argc, char *argv [])
+ fprintf (stdout, "%s\n", message);
+
+ zclock_sleep (50);
++ if (quit && zclock_mono () - start > quit) break;
+ }
+
+ zfile_destroy (&stdinf);