1ZPROC(3)                          CZMQ Manual                         ZPROC(3)
2
3
4

NAME

6       zproc - Class for process configuration and status
7

SYNOPSIS

9       //  This is a draft class, and may change without notice. It is disabled in
10       //  stable builds by default. If you use this in applications, please ask
11       //  for it to be pushed to stable state. Use --enable-drafts to enable.
12       #ifdef CZMQ_BUILD_DRAFT_API
13       //  *** Draft method, for development use, may change without warning ***
14       //  Create a new zproc.
15       //  NOTE: On Windows and with libzmq3 and libzmq2 this function
16       //  returns NULL. Code needs to be ported there.
17       CZMQ_EXPORT zproc_t *
18           zproc_new (void);
19
20       //  *** Draft method, for development use, may change without warning ***
21       //  Destroy zproc, wait until process ends.
22       CZMQ_EXPORT void
23           zproc_destroy (zproc_t **self_p);
24
25       //  *** Draft method, for development use, may change without warning ***
26       //  Return command line arguments (the first item is the executable) or
27       //  NULL if not set.
28       //  Caller owns return value and must destroy it when done.
29       CZMQ_EXPORT zlist_t *
30           zproc_args (zproc_t *self);
31
32       //  *** Draft method, for development use, may change without warning ***
33       //  Setup the command line arguments, the first item must be an (absolute) filename
34       //  to run.
35       CZMQ_EXPORT void
36           zproc_set_args (zproc_t *self, zlist_t **arguments);
37
38       //  *** Draft method, for development use, may change without warning ***
39       //  Setup the command line arguments, the first item must be an (absolute) filename
40       //  to run. Variadic function, must be NULL terminated.
41       CZMQ_EXPORT void
42           zproc_set_argsx (zproc_t *self, const char *arguments, ...);
43
44       //  *** Draft method, for development use, may change without warning ***
45       //  Setup the environment variables for the process.
46       CZMQ_EXPORT void
47           zproc_set_env (zproc_t *self, zhash_t **arguments);
48
49       //  *** Draft method, for development use, may change without warning ***
50       //  Connects process stdin with a readable ('>', connect) zeromq socket. If
51       //  socket argument is NULL, zproc creates own managed pair of inproc
52       //  sockets.  The writable one is then accessbile via zproc_stdin method.
53       CZMQ_EXPORT void
54           zproc_set_stdin (zproc_t *self, void *socket);
55
56       //  *** Draft method, for development use, may change without warning ***
57       //  Connects process stdout with a writable ('@', bind) zeromq socket. If
58       //  socket argument is NULL, zproc creates own managed pair of inproc
59       //  sockets.  The readable one is then accessbile via zproc_stdout method.
60       CZMQ_EXPORT void
61           zproc_set_stdout (zproc_t *self, void *socket);
62
63       //  *** Draft method, for development use, may change without warning ***
64       //  Connects process stderr with a writable ('@', bind) zeromq socket. If
65       //  socket argument is NULL, zproc creates own managed pair of inproc
66       //  sockets.  The readable one is then accessbile via zproc_stderr method.
67       CZMQ_EXPORT void
68           zproc_set_stderr (zproc_t *self, void *socket);
69
70       //  *** Draft method, for development use, may change without warning ***
71       //  Return subprocess stdin writable socket. NULL for
72       //  not initialized or external sockets.
73       CZMQ_EXPORT void *
74           zproc_stdin (zproc_t *self);
75
76       //  *** Draft method, for development use, may change without warning ***
77       //  Return subprocess stdout readable socket. NULL for
78       //  not initialized or external sockets.
79       CZMQ_EXPORT void *
80           zproc_stdout (zproc_t *self);
81
82       //  *** Draft method, for development use, may change without warning ***
83       //  Return subprocess stderr readable socket. NULL for
84       //  not initialized or external sockets.
85       CZMQ_EXPORT void *
86           zproc_stderr (zproc_t *self);
87
88       //  *** Draft method, for development use, may change without warning ***
89       //  Starts the process, return just before execve/CreateProcess.
90       CZMQ_EXPORT int
91           zproc_run (zproc_t *self);
92
93       //  *** Draft method, for development use, may change without warning ***
94       //  process exit code
95       CZMQ_EXPORT int
96           zproc_returncode (zproc_t *self);
97
98       //  *** Draft method, for development use, may change without warning ***
99       //  PID of the process
100       CZMQ_EXPORT int
101           zproc_pid (zproc_t *self);
102
103       //  *** Draft method, for development use, may change without warning ***
104       //  return true if process is running, false if not yet started or finished
105       CZMQ_EXPORT bool
106           zproc_running (zproc_t *self);
107
108       //  *** Draft method, for development use, may change without warning ***
109       //  The timeout should be zero or greater, or -1 to wait indefinitely.
110       //  wait or poll process status, return return code
111       CZMQ_EXPORT int
112           zproc_wait (zproc_t *self, int timeout);
113
114       //  *** Draft method, for development use, may change without warning ***
115       //  send SIGTERM signal to the subprocess, wait for grace period and
116       //  eventually send SIGKILL
117       CZMQ_EXPORT void
118           zproc_shutdown (zproc_t *self, int timeout);
119
120       //  *** Draft method, for development use, may change without warning ***
121       //  return internal actor, useful for the polling if process died
122       CZMQ_EXPORT void *
123           zproc_actor (zproc_t *self);
124
125       //  *** Draft method, for development use, may change without warning ***
126       //  send a signal to the subprocess
127       CZMQ_EXPORT void
128           zproc_kill (zproc_t *self, int signal);
129
130       //  *** Draft method, for development use, may change without warning ***
131       //  set verbose mode
132       CZMQ_EXPORT void
133           zproc_set_verbose (zproc_t *self, bool verbose);
134
135       //  *** Draft method, for development use, may change without warning ***
136       //  Self test of this class.
137       CZMQ_EXPORT void
138           zproc_test (bool verbose);
139
140       #endif // CZMQ_BUILD_DRAFT_API
141       Please add '@interface' section in './../src/zproc.c'.
142

DESCRIPTION

144       zproc - process configuration and status, plus unix pipes on steroids
145
146           Warning
147           zproc class have several limitations atm * is tested on zmq4 on
148           Linux and OSX. * does not work on Windows, where you get empty
149           stubs for most of the methods * does not work on libzmq3 and
150           libzmq2. We have experienced stalls and timeouts when running tests
151           against such old version
152
153       Note: zproc is not yet stable, so there are no guarantees regarding API
154       stability. Some methods can have weird semantics or strange API.
155
156       Class zproc run an external process and to use ZeroMQ sockets to
157       communicate with it. In other words standard input and outputs MAY be
158       connected with appropriate zeromq socket and data flow is managed by
159       zproc itself. This makes zproc the best in class way how to run and
160       manage sub processes.
161
162       Data are sent and received as zframes (zframe_t), so zproc does not try
163       to interpret content of the messages in any way. See test example on
164       how to use it.
165
166           +----------------------------------------+
167           |    /bin/cat cat /etc/passwd            |
168           |    stdin   | stdout      |    stderr   |
169           |------||--------||---------------||-----|
170           |      fd1       fd2              fd3    |
171           |       ^         v                v     |
172           |zmq://stdin |zmq://stdout |zmq://stderr |
173           |         [zproc supervisor]          |
174           +----------------------------------------+
175
176           ----------> zeromq magic here <-----------
177
178           +----------------------------------------+
179           |zmq://stdin |zmq://stdout |zmq://stderr |
180           |                                        |
181           |          consumer                      |
182           |                                        |
183           |                                        |
184           +----------------------------------------+
185
186       Please add @discuss section in ./../src/zproc.c.
187

EXAMPLE

189       From zproc_test method.
190
191           //  variable file contains path to zsp executable:
192           //  char *file = "path/to/zsp";
193
194           #if defined (__WINDOWS__)
195           printf ("Very limited (on Windows) ");
196           {
197               zsys_init ();
198               zproc_t *self = zproc_new ();
199               assert (self);
200
201               zproc_set_verbose (self, verbose);
202               zproc_set_argsx (self, file, "-v", NULL);
203               zproc_run (self);
204               zclock_sleep (100); // to let actor start the process
205               assert (zproc_pid (self));
206
207               zproc_kill (self, SIGTERM);
208               assert (zproc_returncode (self) == 255);
209               zproc_destroy (&self);
210           }
211           printf ("OK\n");
212           return;
213           #endif
214           {
215           // Test case #1: run command, wait until it ends and get the (stdandard) output
216           zproc_t *self = zproc_new ();
217           assert (self);
218           zproc_set_verbose (self, verbose);
219
220           //  join stdout of the process to zeromq socket
221           //  all data will be readable from zproc_stdout socket
222           assert (!zproc_stdout (self));
223           zproc_set_stdout (self, NULL);
224           assert (zproc_stdout (self));
225
226           zproc_set_argsx (self, file, "--help", NULL);
227
228           if (verbose)
229               zsys_debug("zproc_test() : launching helper '%s' --help", file );
230
231           int r = zproc_run (self);
232           assert (r == 0);
233           zframe_t *frame;
234           zsock_brecv (zproc_stdout (self), "f", &frame);
235           assert (frame);
236           assert (zframe_data (frame));
237           // TODO: real test
238           if (verbose)
239               zframe_print (frame, "1:");
240           zframe_destroy (&frame);
241           r = zproc_wait (self, -1);
242           assert (r == 0);
243           zproc_destroy (&self);
244           }
245
246           {
247           // Test case#2: run zsp helper with a content written on stdin, check if it was passed to stdout
248           zproc_t *self = zproc_new ();
249           assert (self);
250           zproc_set_verbose (self, verbose);
251           //  forward input from stdin to stderr
252           zproc_set_argsx (self, file, "--stdin", "--stderr", NULL);
253           // FIXME: there is a BUG in zproc somewhere, you can't gen an output from both stdout/stderr
254           //zproc_set_argsx (self, file, "--stdin", "--stdout", "--stderr", NULL);
255           zproc_set_stdin (self, NULL);
256           // FIXME: the bug
257           //zproc_set_stdout (self, NULL);
258           zproc_set_stderr (self, NULL);
259
260           // send data to stdin
261           int r = zproc_run (self);
262           assert (r == 0);
263           zframe_t *frame = zframe_new ("Lorem ipsum\0\0", strlen ("Lorem ipsum")+2);
264           assert (frame);
265           zsock_bsend (zproc_stdin (self), "f", frame);
266           zframe_destroy (&frame);
267
268           // FIXME: the bug
269           //zproc_set_stdout (self, NULL);
270           // read data from stdout
271           /*
272           zsys_debug ("BAF1");
273           zsock_brecv (zproc_stdout (self), "f", &frame);
274           zsys_debug ("BAF2");
275           assert (frame);
276           assert (zframe_data (frame));
277           if (verbose)
278               zframe_print (frame, "2.stdout:");
279           assert (!strncmp ((char*) zframe_data (frame), "Lorem ipsum", 11));
280           */
281
282           // read data from stderr
283           zsock_brecv (zproc_stderr (self), "f", &frame);
284           assert (frame);
285           assert (zframe_data (frame));
286           if (verbose)
287               zframe_print (frame, "2.stderr:");
288           assert (!strncmp ((char*) zframe_data (frame), "Lorem ipsum", 11));
289           zproc_kill (self, SIGTERM);
290           zproc_wait (self, -1);
291           zframe_destroy (&frame);
292           zproc_destroy (&self);
293           }
294
295           {
296           // Test case#3: run non existing binary
297           zproc_t *self = zproc_new ();
298           assert (self);
299           zproc_set_verbose (self, verbose);
300           //  forward input from stdin to stderr
301           zproc_set_argsx (self, "/not/existing/file", NULL);
302
303           int r = zproc_run (self);
304           assert (r == -1);
305           zproc_destroy (&self);
306           }
307
308           {
309           // Test case #4: child abort itself
310           zproc_t *self = zproc_new ();
311           assert (self);
312           zproc_set_verbose (self, verbose);
313           zproc_set_argsx (self, file, "--verbose", "--abrt", NULL);
314           zproc_set_stdout (self, NULL);
315           zproc_set_stderr (self, NULL);
316           zproc_set_stdin (self, NULL);
317
318           int r = zproc_run (self);
319           zclock_sleep (100); // to let actor start the process
320           assert (r != -1);
321           zclock_sleep (100);
322           zframe_t *frame;
323           zsock_brecv (zproc_stdout (self), "f", &frame);
324           assert (zframe_is (frame));
325           assert (zframe_size (frame) > 0);
326           zframe_destroy (&frame);
327           zproc_wait (self, -1);
328           assert (zproc_returncode (self) == -SIGABRT);
329           zproc_destroy (&self);
330           }
331
332           {
333           // Test case #5: use never ending subprocess and poller to read data from it
334           //  Create new zproc instance
335           zproc_t *self = zproc_new ();
336           assert (self);
337           zproc_set_verbose (self, verbose);
338           //  join stdout of the process to zeromq socket
339           //  all data will be readable from zproc_stdout socket
340           zproc_set_stdout (self, NULL);
341
342           zlist_t *args = zlist_new ();
343           zlist_autofree (args);
344           zlist_append (args, file);
345           zlist_append (args, "--stdout");
346           zproc_set_args (self, &args);
347
348           zhash_t *env = zhash_new ();
349           zhash_autofree (env);
350           zhash_insert (env, "ZSP_MESSAGE", "czmq is great\n");
351           zproc_set_env (self, &env);
352
353           // execute the binary. It runs in own actor, which monitor the process and
354           // pass data accross pipes and zeromq sockets
355           if (verbose)
356               zsys_debug("zproc_test() : launching helper '%s'", file );
357           zproc_run (self);
358           zpoller_t *poller = zpoller_new (zproc_stdout (self), NULL);
359
360           // kill the binary, it never ends, but the test must:
361           // termination also flushes the output streams so we can
362           // read them entirely; note that other process runs in
363           // parallel to this thread
364           if (verbose)
365               zsys_debug("zproc_test() : sleeping 4000 msec to gather some output from helper");
366           zclock_sleep (4000);
367           zproc_kill (self, SIGTERM);
368           zproc_wait (self, -1);
369
370           // read the content from zproc_stdout - use zpoller and a loop
371           bool stdout_read = false;
372           int64_t zproc_timeout_msec = 10000;
373           int64_t zproc_test_start_msec = zclock_mono();
374           int64_t zproc_test_elapsed_msec = 0;
375
376           while (!zsys_interrupted) {
377               void *which = zpoller_wait (poller, 800);
378               zproc_test_elapsed_msec = zclock_mono() - zproc_test_start_msec;
379
380               if (!which) {
381                   if (stdout_read) {
382                       if (verbose)
383                           zsys_debug("zproc_test() : did not get stdout from helper, but we already have some (%" PRIi64 " msec remaining to retry)", (zproc_timeout_msec - zproc_test_elapsed_msec) );
384                       break;
385                   }
386                   if (zproc_timeout_msec > zproc_test_elapsed_msec) {
387                       if (verbose)
388                           zsys_debug("zproc_test() : did not get stdout from helper, %" PRIi64 " msec remaining to retry", (zproc_timeout_msec - zproc_test_elapsed_msec) );
389                       continue;
390                   }
391                   // ...else : we've slept a lot and got no response; kill the helper
392                   if (verbose)
393                       zsys_debug("zproc_test() : did not get stdout from helper, patience expired (%" PRIi64 " msec remaining to retry)", (zproc_timeout_msec - zproc_test_elapsed_msec) );
394                   break;
395               }
396
397               if (which == zproc_stdout (self)) {
398                   // it suffices for us to have read something
399                   // we only check the first frame, others may start with the
400                   // expected key string broken mid-way due to alignment etc.,
401                   // but we drain the whole incoming queue of stdout frames.
402                   zframe_t *frame;
403                   zsock_brecv (zproc_stdout (self), "f", &frame);
404                   assert (frame);
405                   assert (zframe_data (frame));
406                   if (!stdout_read) {
407                       if (verbose)
408                           zsys_debug("zproc_test() : got stdout from helper, %" PRIi64 " msec was remaining to retry", (zproc_timeout_msec - zproc_test_elapsed_msec));
409                       assert (!strncmp(
410                           "czmq is great\n",
411                           (char*) zframe_data (frame),
412                           14));
413                       stdout_read = true;
414                   }
415
416                   if (verbose)
417                       zframe_print (frame, "zproc_test");
418
419                   zframe_destroy (&frame);
420                   continue;
421               }
422
423               // should not get there
424               if (verbose)
425                   zsys_debug("zproc_test() : reached the unreachable point (unexpected zpoller result), %" PRIi64 " msec was remaining to retry", (zproc_timeout_msec - zproc_test_elapsed_msec) );
426               assert (false);
427           }
428
429           assert (stdout_read);
430           zpoller_destroy (&poller);
431           zproc_destroy (&self);
432           }
433           {
434           // testcase #6 wait for process that hangs, kill it
435           zproc_t *self = zproc_new ();
436           assert (self);
437           zproc_set_verbose (self, verbose);
438
439           zproc_set_argsx (self, file, NULL);
440
441           if (verbose)
442               zsys_debug("zproc_test() : launching helper '%s'", file);
443
444           int r = zproc_run (self);
445           assert (r == 0);
446           r = zproc_wait (self, 1000);
447           assert (r == ZPROC_RUNNING);
448           assert (zproc_running (self));
449           zproc_shutdown (self, 1000);
450           assert (!zproc_running (self));
451           zproc_destroy (&self);
452           }
453           {
454           // testcase #7 wait for process that exits earlier
455           zproc_t *self = zproc_new ();
456           assert (self);
457           zproc_set_verbose (self, verbose);
458
459           zproc_set_argsx (self, file, "--quit", "1", NULL);
460
461           if (verbose)
462               zsys_debug("zproc_test() : launching helper '%s' --quit 1", file);
463
464           int r = zproc_run (self);
465           assert (r == 0);
466           int t = zclock_mono ();
467           r = zproc_wait (self, 8000);
468           assert (r == 0);
469           t = zclock_mono () - t;
470           assert (t < 2000);
471           zproc_destroy (&self);
472           }
473
474

AUTHORS

476       The czmq manual was written by the authors in the AUTHORS file.
477

RESOURCES

479       Main web site:
480
481       Report bugs to the email <zeromq-dev@lists.zeromq.org[1]>
482
484       Copyright (c) the Contributors as noted in the AUTHORS file. This file
485       is part of CZMQ, the high-level C binding for 0MQ:
486       http://czmq.zeromq.org. This Source Code Form is subject to the terms
487       of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
488       distributed with this file, You can obtain one at
489       http://mozilla.org/MPL/2.0/. LICENSE included with the czmq
490       distribution.
491

NOTES

493        1. zeromq-dev@lists.zeromq.org
494           mailto:zeromq-dev@lists.zeromq.org
495
496
497
498CZMQ 4.2.1                        07/19/2023                          ZPROC(3)
Impressum