is libonion's event loop supposed to be usable by the application for other purposes?

38 views
Skip to first unread message

Basile Starynkevitch

unread,
Jul 1, 2018, 6:47:47 AM7/1/18
to onion-dev
Hello All,

Assuming a libonion configured without libevent or libev. Is the event loop used by libonion supposed to be usable by the application using libonion, outside of HTTP service?

For example, how should be mix some JSONRPC service with that event loop? Or some X11 application above X? Ot some SMTP client or server? Or use some HTTP client capabilities with libcurl?

It looks that the philosophy under libonion is to have the application use another thread for its event loop?

To be specific, most other libraries providing some event loop are provided a well documented way to hook and reuse that loop for other purposes. For example GTK has gtk_main but also its GMainLoop and g_source_add_unix_fd etc (and also GIO). libcurl has a a multi-interface, curl_multi_fd_set, etc.. Qt provides not only QApplication::exec but also QSocketNotifier (poorly named, can be used on pipe(7)-s..)

Is the libonion's poller.h interface expected to fullfil that purpose? I guess that yes, but I am not sure!

And how should be libonion used if on the contrary we want to incorporate it into some existing event loop machinery (e.g. GTK's one, or Qt's one, or libcurl's one) - without dedicating a thread for libonion?

This of course is also related to issue #229 (I believe that once I'm understanding how to extend libonion's event loop I would be able to propose a patch for that issue). But I also want to fork a few processes (whose `stdin` is redirected from `/dev/null`) and poll the pipe-s carrying their stdout (à la popen) but without creating a thread.

My intuition (perhaps a wrong one) is that threads are really expensive, and I am reluctant to have several event loops served by different threads.  If I did that, I'll still have some synchronization issues between them.

Regards.
--
Bourg La Reine, France

Zachary Grafton

unread,
Jul 1, 2018, 10:53:09 PM7/1/18
to onion-dev
Basile,

I think that I wouldn't use the epoll based event loop anywhere but on it's own thread. The poller interface needs a little bit of a redesign, and I think David was doing some work on that at one point in time on a separate branch.

No matter what you try, I would definitely set O_NO_SIGTERM flag when calling onion_new. As you've pointed out, the signal handling code isn't safe. I had plans to tackle that issue at one point in time, but came to the conclusion that the best way for libonion to handle signals is to just not handle signals and I never had the chance to discuss it with David.


Zack
Bourg La Reine, France

Basile Starynkevitch

unread,
Jul 2, 2018, 12:54:25 AM7/2/18
to Zachary Grafton, onion-dev



On 07/02/2018 04:53 AM, Zachary Grafton wrote:
Basile,

I think that I wouldn't use the epoll based event loop anywhere but on it's own thread. The poller interface needs a little bit of a redesign, and I think David was doing some work on that at one point in time on a separate branch.

No matter what you try, I would definitely set O_NO_SIGTERM flag when calling onion_new. As you've pointed out, the signal handling code isn't safe.


But my question could be rephrased as: is it wise to re-use libonion's event loop (and its polling thread) for something else (i.e. internal needs of my application)?

My actual use case is the following. My bismon program (currently at commit ccda0331ba4f9583a521e2d7a0a44c5; it temporarily has both a GTK and a libonion variant) needs a queue_process_BM function (currently not implemented yet when using libonion, see file web_ONIONBM.c line 111, but only implemented when using GTK in file newgui_GTKBM.c line 4026). That function is (a bit like popen with "r" mode) forking an external process, whose stdin is redirected to /dev/null, and whose stdout and stderr are going into a pipe. That pipe is read by bismon, all the data on it (the output of the forked process) is collected in a buffer. So I need to poll that pipe and read it. I would prefer that to happen in some libonion's thread and avoid creating my specific thread for it (with GTK I use g_io_add_watch, not sure how to do that with libonion).


Regards
-- 
Basile STARYNKEVITCH   == http://starynkevitch.net/Basile
opinions are mine only - les opinions sont seulement miennes
Bourg La Reine, France

Basile Starynkevitch

unread,
Jul 2, 2018, 4:27:47 AM7/2/18
to onion-dev, zachary...@gmail.com


On Monday, July 2, 2018 at 6:54:25 AM UTC+2, Basile Starynkevitch wrote:



On 07/02/2018 04:53 AM, Zachary Grafton wrote:
 
But my question could be rephrased as: is it wise to re-use libonion's event loop (and its polling thread) for something else (i.e. internal needs of my application)?
 

A related question is: can we use onion_listen_stop outside of onion callbacks  in some other thread (not started by onion)? That is, I will start my own event loop in my own thread (imagine that event loop is serving some JSONRPC service, or is the GTK main loop running with gtk_main)

I would like to do that, but then I guess there is a bug in onion_listen_stop (which I believe is not thread-friendly). It should use the mutex. The pull request #230 fixes that.

Regards
--

Basile Starynkevitch <bas...@starynkevitch.net>

David Moreno Montero

unread,
Jul 3, 2018, 3:52:04 AM7/3/18
to Basile Starynkevitch, onion-dev, Zachary Grafton
Hi,

it should be possible to use the onion poller for your needs (stdout to onion: onion_poller_slot_new + onion_polled_add), or use another poller.

To use another poller I suggest you look at the poller_libev.c or poller_libevent.c and just re implement the same functions using the GTK/X11 poller, as the gtk one. (if you feel like, please contribute it back!)

Anyway I would just use the detached thread version, as threads are not expensive on Linux. I would expect the same or very similar performance as when used non-detached version, and slightly more memory use (4MB maybe). And in any case I would benchmark it if performance is very important.

To the best of my knowledge onion_listen_stop can be called anywhere. The PR #230 I dont think was strictly necessary, but has been merged for correctness.

Regards,
David,

--
You received this message because you are subscribed to the Google Groups "onion-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to onion-dev+unsubscribe@coralbits.com.
To post to this group, send email to onio...@coralbits.com.
Visit this group at https://groups.google.com/a/coralbits.com/group/onion-dev/.
For more options, visit https://groups.google.com/a/coralbits.com/d/optout.



--

Basile Starynkevitch

unread,
Jul 3, 2018, 7:07:48 AM7/3/18
to David Moreno Montero, onion-dev, Zachary Grafton
On 2018-07-03 09:51, David Moreno Montero wrote:
> Hi,
>
> it should be possible to use the onion poller for your needs (stdout
> to onion: onion_poller_slot_new + onion_polled_add), or use another
> poller.
>
> To use another poller I suggest you look at the poller_libev.c or
> poller_libevent.c and just re implement the same functions using the
> GTK/X11 poller, as the gtk one. (if you feel like, please contribute
> it back!)
>
> Anyway I would just use the detached thread version, as threads are
> not expensive on Linux. I would expect the same or very similar
> performance as when used non-detached version, and slightly more
> memory use (4MB maybe). And in any case I would benchmark it if
> performance is very important.

A big thanks for your reply (and merging of pull request #230)

Performance is not essential for me (because I would have in practice
only a few browsers
using my bismon application, see https://github.com/bstarynk/bismon for
more); I actually don't care much
about libonion related performance!

Correctness (i.e. lack of known data races) is much more important to me
(and robust handling of SIGTERM and SIGQUIT).

However, even if threads are not expensive on Linux, I am trying to not
have too much of them, in particular because I am implementing
some naive but precise garbage collector (I am quite ashamed of my code,
the GC might be buggy and is certainly not efficient;
I would dream of using ravenbook's MPS, see
https://www.ravenbrook.com/project/mps for more,
but it requires to be notified -or at least aware- of every allocation
and of every thread; look into
http://mailman.ravenbrook.com/pipermail/mps-discussion/2018-January/000212.html
etc for more)
So when my GC is running, I need to be sure that no thread at all
(including those started by libonion) could allocate memory (in the
sense
of my GC). In other words, my naive GC (remember, I am ashamed of it,
but at this point I want only to make
a proof-of-concept software, since BISMON is funded by an H2020 RIA
project http://www.chariotproject.eu/ today)
is simply a stop-the-world marking GC.


Another reason to avoid threads is that I don't understand very well how
to mix synchronization with condition variables & mutexes
(in the PTHREAD sense) and event loops (running in several threads)
without any race conditions (the point is that both
pthread_cond_wait(3) and poll(2) -or read(2)- are blocking, and there
seems no reliable way to block till either a pthread_cond is notified
or some file descriptor gets ready). It looks like I need to use pipes
(or at least Linux eventfd-s) between such event loops.
I tend to believe that Qt has the same issue (and solves it by requiring
essentially every thread to run some Qt event loop).
If anyone has some insight about that, please tell.

This is related of course to the signal issues I have raised earlier.
libonion issue #229 (and the messages linked there)

Cheers.

--
Basile Starynkevitch http://starynkevitch.net/Basile
France (opinions are only mine)

David Moreno Montero

unread,
Jul 3, 2018, 7:22:28 AM7/3/18
to Basile Starynkevitch, onion-dev, Zachary Grafton
Hi,

I dont have time now to anwser all, but just remark that libonion always uses onion_low_malloc and family, so it can be integrated with your custom GC.

The synchronization in the epoll poller works as the kernel wakes up only one thread (and have some affinity herustics). And onion avoids as much as possible to share data: no sharing no need for synchronization. But each thread could block and eventually run out of threads in the pool.

Did I say I love Erlang? They solve most of these problems just using other techniques and embracing processes, functional programming, supervisors and so on.

Regards,
David.



--
You received this message because you are subscribed to the Google Groups "onion-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to onion-dev+unsubscribe@coralbits.com.
To post to this group, send email to onio...@coralbits.com.
Visit this group at https://groups.google.com/a/coralbits.com/group/onion-dev/.
For more options, visit https://groups.google.com/a/coralbits.com/d/optout.

Basile Starynkevitch

unread,
Jul 3, 2018, 8:23:33 AM7/3/18
to David Moreno Montero, onion-dev, Zachary Grafton
On 2018-07-03 13:22, David Moreno Montero wrote:
> Hi,
>
> I dont have time now to anwser all, but just remark that libonion
> always uses onion_low_malloc and family, so it can be integrated with
> your custom GC.
>

This is not enough for a precise GC (notably Ravenbrook's MPS, mentioned
in previous email). Which needs to know explicitly every pointer (and
changes them inside its own SIGSEGV handlers - yes Ravenbrook team is
using high-tech stuff : their code is very tricky and mutates GC-ed
pointers in SIGSEGV and SIGBUS handlers in a safe way -related to write
barriers- inside multithreaded applications).

onion_low_malloc (with onion_low_pthread_create) is enough with for
Bohm's GC, which is conservative. But to be usable with MPS, we need a
marking routine for every onion type. This is probably too much work,
and is brittle (but look also into
https://github.com/clasp-developers/clasp for inspiring some other
approach).

Multi-threaded generational precise GC are really tricky and requires a
lot of work (e.g. several years full time, which I cannot afford).

Cheers
Reply all
Reply to author
Forward
0 new messages