Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IPC: server: avoid temporary channel priority loss, up to deadlock-worth #352

Merged
2 changes: 2 additions & 0 deletions .travis.yml
Expand Up @@ -8,6 +8,8 @@ addons:
packages:
- check
- splint
# for ipc.test:test_ipc_dispatch_*_deadlock_provoke
- libglib2.0-dev # natively present, but doesn't hurt
# for "make rpm"
- doxygen
- rpm
Expand Down
22 changes: 22 additions & 0 deletions include/qb/qbipcs.h
Expand Up @@ -43,6 +43,12 @@ extern "C" {
* @example ipcserver.c
*/

/**
* Rates to be passed to #qb_ipcs_request_rate_limit. The exact interpretation
* depends on how the event loop implementation understands the concept of
* priorities, see the discussion at #qb_ipcs_poll_handlers structure -- an
* integration point between IPC server instance and the underlying event loop.
*/
enum qb_ipcs_rate_limit {
QB_IPCS_RATE_FAST,
QB_IPCS_RATE_NORMAL,
Expand Down Expand Up @@ -104,6 +110,22 @@ typedef int32_t (*qb_ipcs_job_add_fn)(enum qb_loop_priority p,
void *data,
qb_loop_job_dispatch_fn dispatch_fn);

/**
* A set of callbacks that need to be provided (only #job_add can be #NULL)
* whenever the IPC server is to be run (by the means of #qb_ipcs_run).
* It is possible to use accordingly named functions defined in qbloop.h module
* or integrate with other existing (like GLib's event loop) or entirely new
* code -- see the subtle distinction amongst the possible event loops pointed
* out in the introductory comment at qbloop.h.
*
* At that occasion, please note the correlation of #QB_IPCS_RATE_FAST etc.
* symbolic names with said advisory effect of the priorities in the native
* implementation. This correspondence will not be this intuitively seemless
* if some other event loop implementation is hooked in given that it abids
* them strictly as mentioned (e.g. GLib's event loop over poll'able sources).
* Differences between the two paradigms should also be accounted for when
* the requirement to swap the event loop implementations arises.
*/
struct qb_ipcs_poll_handlers {
qb_ipcs_job_add_fn job_add;
qb_ipcs_dispatch_add_fn dispatch_add;
Expand Down
20 changes: 20 additions & 0 deletions include/qb/qbloop.h
Expand Up @@ -36,6 +36,26 @@ extern "C" {
*
* Main loop manages timers, jobs and polling sockets.
*
* Only a weaker sense of priorities is implemented, alluding to distinct
* set of pros and cons compared to the stronger, strict approach to them
* as widely applied in this problem space (since the latter gives the
* application more control as the effect of the former can still be
* achieved with some reductions, whereas it is not straightforward the
* other way around; cf. static priority task scheduling vs. relative
* fine-tuning within a single priority domain with nice(2)):
*
* + implicit mitigation for deadlock-prone priority arrangements
*
* - less predictable (proportional probability based, we can talk
* about an advisory effect of the priorities) responses to the arrival
* of the high-ranked events (i.e. in the process of the picking the next
* event to handle from the priority queue when at least two different
* priorities are eligible at the moment)
*
* One practical application for this module of libqb is in combination with
* IPC servers based on qbipcs.h published one (the #qb_ipcs_poll_handlers
* structure maps fittingly to the control functions published here).
*
* @example tcpserver.c
*/

Expand Down
11 changes: 6 additions & 5 deletions lib/ipc_setup.c
Expand Up @@ -825,12 +825,13 @@ qb_ipcs_uc_recv_and_auth(int32_t sock, struct qb_ipcs_service *s)
setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
#endif

res = s->poll_fns.dispatch_add(QB_LOOP_MED,
data->sock,
POLLIN | POLLPRI | POLLNVAL,
data, process_auth);
res = s->poll_fns.dispatch_add(s->poll_priority,
data->sock,
POLLIN | POLLPRI | POLLNVAL,
data, process_auth);
if (res < 0) {
qb_util_log(LOG_DEBUG, "Failed to process AUTH for fd (%d)", data->sock);
qb_util_log(LOG_DEBUG, "Failed to arrange for AUTH for fd (%d)",
data->sock);
close(sock);
destroy_ipc_auth_data(data);
}
Expand Down
5 changes: 5 additions & 0 deletions tests/Makefile.am
Expand Up @@ -167,6 +167,11 @@ ipc_test_LDADD = $(top_builddir)/lib/libqb.la @CHECK_LIBS@
if HAVE_FAILURE_INJECTION
ipc_test_LDADD += _failure_injection.la

if HAVE_GLIB
ipc_test_CFLAGS += $(GLIB_CFLAGS)
ipc_test_LDADD += $(GLIB_LIBS)
endif

check_LTLIBRARIES += _failure_injection.la
_failure_injection_la_SOURCES = _failure_injection.c _failure_injection.h
_failure_injection_la_LDFLAGS = -module
Expand Down