Connecting to systemd DBUS signals using gdbus-codegen - dbus

I am not able to receive systemd DBus signals when using gdbus-codegen generated manager proxy. But I am able to successfully call methods provided by systemd over DBus.
I searched online and looked these links without much success. There aren't much examples on how to do it when gdbus-codegen is used for systemd API.
https://developer.gnome.org/gio/stable/gdbus-codegen.html
http://www.freedesktop.org/software/gstreamer-sdk/data/docs/latest/gio/ch30s05.html
Here is what I did along with code snippets.
1) I generated systemd introspection and used that XML as input to gdbus-codegen.
...snip
<interface name="org.freedesktop.systemd1.Manager">
<signal name="JobRemoved">
<arg type="u"/> <arg type="o"/> <arg type="s"/> <arg type="s"/>
</signal>
...snip
2) Wrote my client code to use C APIs generated by gdbus-codegen and created a manager proxy. (Everything is on system bus).
SystemdManager *systemdProxy = systemd_manager_proxy_new_for_bus_sync(
G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE,
"org.freedesktop.systemd1", "/org/freedesktop/systemd1",
NULL, error);
3) Define a signal handler
static void on_done(GDBusProxy *proxy,
gchar *sender_name,
gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
LOG_ERROR("on_done");
}
4) Connected a signal handler to that proxy for JobRemoved signal.
if (g_signal_connect(systemdProxy, "job-removed",
G_CALLBACK(on_done), NULL) <= 0 )
{
LOG_ERROR("Failed to connect to signal job-removed");
}
5) Used the proxy to start a systemd service. This returns success and I could see the unit start and run for a second or two and terminate.
ret = systemd_manager_call_start_unit_sync(
systemdProxy, unit_name, unit_mode, &job_obj,
NULL, &error);
6) systemd generates a JobRemoved signal. dbus-monitor shows it.
signal sender=:1.0 -> dest=(null destination) serial=11931
path=/org/freedesktop/systemd1;
interface=org.freedesktop.systemd1.Manager;
member=JobRemoved
uint32 7009
object path "/org/freedesktop/systemd1/job/7009"
string "mysample.service"
string "done"
7) My signal handler never gets called. (Everything uses system bus, there are no other buses). I have tried various strings for detailed_signal 2nd parameter for g_signal_connect (like: JobRemoved, job_removed, ::job-removed, some are not accepted by g_signal_connect).
Any help is greatly appreciated!

The solution was to use a glib event loop in my program. My program did not have a running GMainLoop which was necessary to get any callbacks from glib. This is not an elegant way but for various reasons I decided to spawn a new thread which would then block on g_main_loop_run. Here is how it looks like.
void *event_loop_thread(void *unused) {
GMainLoop *loop = g_main_loop_new(NULL, 0);
g_main_loop_run(loop);
}
int main() {
// snip
pthread_create(&thread_id, NULL, event_loop_thread, NULL);
// do steps 2 to 6, and at step 7 signal handler is called
}
Also I had to fix my signal handler signature to be compatible with the signal to receive meaningful parameters.
static void on_done(SystemdManager *manager,
guint32 job_id,
gchar *job_obj,
gchar *unit_name,
gchar *status)
{
LOG_ERROR("on_done");
}

Related

How can I call a Gtk API from another thread?

I've written a C program in which I implemented some threads to make polling. When something happens in the thread I have to modify some Widgets created in main function.
This program sometimes crashes when a thread tries to do an operation on a Widget, for example simply calling the function gtk_widget_hide, and I discovered that's because I must not call any GTK API from another thread.
How can I do what I've described before avoiding any crashes? Is it possible, considering I need threads?
That's an example of what my code does
static GtkWidget* widget;
void check_user_action(){
while(!user_does_action){
g_sleep(1);
}
gtk_widget_hide(main_widget);
}
void main(){
widget = //I skip widget creation
gtk_widget_show_all(widget);
g_thread_new("check_user_action", check_user_action, NULL);
//do something else
}
That's only an example, but assume the only way I have to check_user_action is with polling.
For your snippet you can pass the task to your main thread:
gboolean my_hide_func(gpointer user_data)
{
gtk_widget *widget = (gtk_widget*) user_data;
gtk_widget_hide(widget);
return FALSE;
}
void check_user_action(){
while(!user_does_action){
g_sleep(1);
}
g_idle_add(my_hide_func, main_widget);
}
This will enqueue a request to call that function in the queue for the main thread running your GTK application.

GFileMonitor - g_signal_handler_block "changed" signal doesn't block handler?

All,
This may take a moment to set up. I have a small editor project I've worked on the past several months[1]. I originally wanted to implement an inotify watch on the current editor file to protect against modification by a foreing process. I created a custom signal, and routines to add, remove, and monitor (with pselect) the watch and routines to block and unblock emission of the custom signal to allow for normal save/save as without triggering the callback. The problem I had was how to add the monitor to the gtk_event_loop so that a check was performed on each iteration of the loop. I settled on using g_idle_add and went to the gtk-app-devel list to determine if the approach was reasonable or if there was a better way. The concensus was to use GIO/GFileMonitor instead of working with inotify directly.
Fast forward to the current problem. I rewrote the implementation to use GFileMonitor/g_file_monitor_file and rewrote the block and unblock routines to block handling of the "changed" signal to allow a normal save/save as without firing the callback. The problem is when I block the instance and handler_id for the callback before saving the file, the callback still fires. When using the inotify implementation with a custom signal, blocking the emission of the signal worked great. I have posted this back to the gtk-app-devel list, but have received nothing in return -- that's why I'm asking here. Why does g_signal_handler_block with the GIO/GFileMonitor not block handling to the "changed" signal callback? (more importantly, how do I fix it)
note: (MCVE - complete test code is at https://github.com/drankinatty/gtktest). To build with GtkSourceView2, simply type make with=-DWGTKSOURCEVIEW2, it will build as bin/gtkwrite, otherwise to build without, simply type make and it will build as bin/gtkedit.
The logic of the relevant code is as follows (app is an instance of the struct holding relevant editor variables/info and settings) The GIO/GFileMonitor implementation is in gtk_filemon.[ch] and the wrapper around the save function is in gtk_filebuf.c:
typedef struct {
...
gchar *filename;
GFileMonitor *filemon;
gulong mfp_handler;
...
} kwinst;
kwinst *app = g_slice_new (kwinst);
I set the watch with:
GFile *gfile = g_file_new_for_path (app->filename);
...
/* create monitor for app->filename */
app->filemon = g_file_monitor_file (gfile,
G_FILE_MONITOR_NONE,
cancellable, &err);
...
/* connect changed signal to monitored file saving ID */
app->mfp_handler = g_signal_connect (G_OBJECT(app->filemon), "changed",
G_CALLBACK (file_monitor_on_changed), data);
Both the instance (app->filemon) and handler_id (app->mfp_handler) are saved. (mfp is just short for modified by foreign process) In order to prevent handling of changes during normal save/save as operations, I created block and unblock functions to prevent the changes to the file from firing the callback, e.g. show below with debug g_print calls:
void file_monitor_block_changed (gpointer data)
{
kwinst *app = (kwinst *)data;
if (!app->filemon || !app->mfp_handler) return;
g_print ("blocking changed (%lu)\n", app->mfp_handler);
g_signal_handler_block (app->filemon, app->mfp_handler);
}
void file_monitor_unblock_changed (gpointer data)
{
kwinst *app = (kwinst *)data;
if (!app->filemon || !app->mfp_handler) return;
g_print ("unblocking changed (%lu)\n", app->mfp_handler);
g_signal_handler_unblock (app->filemon, app->mfp_handler);
}
To implement the block/unblock, I wrap the file 'save/save as' function with the block, then save[2], then unblock, but the callback is still firing on normal saves. e.g. the relevant part of the save function I have is:
if (app->mfp_handler) /* current file monitor on file */
file_monitor_block_changed (app); /* block "changed" signal */
g_print (" buffer_write_file (app, filename)\n");
buffer_write_file (app, filename); /* write to file app->filename */
if (filename)
file_monitor_add (app); /* setup monitoring on new name */
else if (app->mfp_handler)
file_monitor_unblock_changed (app); /* unblock "changed" signal */
With the debug g_print statements above, issuing save results in the following output:
$ ./bin/gtkwrite
blocking changed (669)
buffer_write_file (app, filename)
unblocking changed (669)
Monitor Event: File = /home/david/tmp/foo.txt.UY9IXY
G_FILE_MONITOR_EVENT_DELETED
Monitor Event: File = /home/david/tmp/foo.txt
G_FILE_MONITOR_EVENT_CREATED
Monitor Event: File = /home/david/tmp/foo.txt
G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT
Monitor Event: File = /home/david/tmp/foo.txt
G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED
It makes no difference whether I include the block/unblock, the firing of the callback is unchanged. I suspect that the problem lies in the fact that the "changed" signal and it handling are implemented through GIO rather than GTK (as the custom signal for the inotify implementation was) and there being some difference in the abiliby to block handling of the "changed" signal using g_signal_handler_block -- though I cannot find a distinction in the documentation. The documentation states:
To get informed about changes to the file or directory you are monitoring,
connect to the “changed” signal. The signal will be emitted in the thread-default
main context of the thread that the monitor was created in (though if the global
default main context is blocked, this may cause notifications to be blocked
even if the thread-default context is still running).
https://developer.gnome.org/gio/stable/GFile.html#g-file-monitor-file
The application itself makes no use of any explicit threading and does not fork any part of the save. So I'm at a loss as to why the block/unblock does not prevent handling of the "changed" signal. The save is completely wrapped in the block/unblock, unless the g_file_set_contents call is asyncronous, there shouldn't be any timing issues I can see.
Why would calls to g_signal_handler_block/g_signal_handler_unblock fail to prevent handling of the "changed" signal emitted on changes to the current file? I can g_signal_handler_disconnect and nothing fires, but I shouldn't have to disconnect to temporarily block handling. What am I missing?
For completeness the file_monitor_on_changed function is included below along with the footnotes:
void file_monitor_on_changed (GFileMonitor *mon,
GFile *file, GFile *other,
GFileMonitorEvent evtype,
gpointer data)
{
kwinst *app = (kwinst *)data;
g_print ("Monitor Event: File = %s\n", g_file_get_parse_name (file));
switch (evtype)
{
case G_FILE_MONITOR_EVENT_CHANGED:
/* prompt or emit custom signal modified by foreign process */
g_print ("G_FILE_MONITOR_EVENT_CHANGED\n");
break;
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
g_print ("G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT\n");
break;
case G_FILE_MONITOR_EVENT_DELETED:
/* avoid firing on normal '.tmp' file delete */
if (g_strcmp0 (g_file_get_parse_name (file), app->filename)) {
g_print (" ignoring 'tmp' file delete.\n");
break;
}
/* prompt or emit custom signal modified by foreign process */
g_print ("G_FILE_MONITOR_EVENT_DELETED\n");
/* prompt save file */
break;
case G_FILE_MONITOR_EVENT_CREATED:
g_print ("G_FILE_MONITOR_EVENT_CREATED\n");
break;
case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
g_print ("G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED\n");
break;
case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
g_print ("G_FILE_MONITOR_EVENT_PRE_UNMOUNT\n");
break;
case G_FILE_MONITOR_EVENT_UNMOUNTED:
g_print ("G_FILE_MONITOR_EVENT_UNMOUNTED\n");
break;
case G_FILE_MONITOR_EVENT_MOVED:
g_print ("G_FILE_MONITOR_EVENT_MOVED\n");
/* prompt save file */
break;
case G_FILE_MONITOR_EVENT_RENAMED:
/* prompt save file */
g_print ("G_FILE_MONITOR_EVENT_RENAMED\n");
break;
case G_FILE_MONITOR_EVENT_MOVED_IN:
g_print ("G_FILE_MONITOR_EVENT_MOVED_IN\n");
break;
case G_FILE_MONITOR_EVENT_MOVED_OUT:
g_print ("G_FILE_MONITOR_EVENT_MOVED_OUT\n");
break;
default:
g_print ("unknown EVENT on changed signal.\n");
}
if (mon || other) {}
}
Using g_signal_handler_block works fine in other cases
As a point brought up in the comments, I can confirm I can easily block, unblock other signal handlers without issues. Specifically, when working with the inotify implementation, I created the following custom signal:
/* create signal to monitor file modified by foreign process */
app->SIG_MODFP = g_signal_new ("modified-foreign",
GTK_TYPE_TEXT_BUFFER,
GTK_RUN_ACTION,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
1,
G_TYPE_POINTER);
Then connecting the signal to a handler and saving the handler_id as follows:
/* custom signals */
app->mfp_handler2 = g_signal_connect (GTK_TEXT_BUFFER(app->buffer),
"modified-foreign",
G_CALLBACK (on_modified_foreign), app);
The on_modified_foreign callback is a simple test callback for purposes of testing the block/unblock:
void on_modified_foreign (GtkTextBuffer *buffer,
kwinst *app)
{
dlg_info ("File has changed on disk, reload?", "Modified by Foreign Process");
if (buffer || app) {}
}
Above dlg_info is just a wrapper to gtk_message_dialog_new to pop up a dialog when the "modified-foreign" signal is emitted.
Then implementing a simple test where one menuitem causes the signal to be emitted, e.g.:
void menu_status_bigredbtn_activate (GtkMenuItem *menuitem, kwinst *app)
{
g_signal_emit_by_name (G_OBJECT(app->buffer), "modified-foreign::", app);
}
And, finally blocking/unblocking works just fine:
void menu_status_block_activate (GtkMenuItem *menuitem, kwinst *app)
{
if (!app->mfp_handler2) return;
GtkTextBuffer *buffer = GTK_TEXT_BUFFER(app->buffer);
g_signal_handler_block (buffer, app->mfp_handler2);
}
void menu_status_unblock_activate (GtkMenuItem *menuitem, kwinst *app)
{
if (!app->mfp_handler2) return;
GtkTextBuffer *buffer = GTK_TEXT_BUFFER(app->buffer);
g_signal_handler_unblock (buffer, app->mfp_handler2);
}
It all works fine. Select the bigredbtn menu item, the signal is emitted and up pops the dialog. Then selecting the block menu item and then again trying the bigredbtn -- nothing happens, no dialog, no nothing. Then selecting the unblock menu item and again selecting the bigredbtn, the dialog again pops up on each selection. (and the signals emitted while the handler was blocked were not queued and do not invoke the handler once it is unblocked)
So that is where I'm stuck. A large part of the problem is without picking though the GIO source line-by-line it, to a large extent, is a big black box. All works fine on the GTK side, but when doing the same thing involving a GIO function, the results seem not to work as expected.
Thanks for any other insight you may have on this issue.
footnote 1: https://github.com/drankinatty/gtkwrite
footnote 2: buffer_write_file calls g_file_set_contents to write to disk.
Ok, I've played with it long enough, and I've found a solution. The key seems to be, for whatever reason in the grand scheme of GIO, to call the block and unblock from within the same source that the signals were originally connected in. For example, adding block/unblock functions within the gtk_filemon.c source and then calling from anywhere (as done from a test menu item above) works fine, e.g.:
void file_monitor_block_changed (gpointer data)
{
kwinst *app = (kwinst *)data;
if (!app->filemon || !app->mfp_handler) return;
g_signal_handler_block (app->filemon, app->mfp_handler);
}
void file_monitor_unblock_changed (gpointer data)
{
kwinst *app = (kwinst *)data;
if (!app->filemon || !app->mfp_handler) return;
g_signal_handler_unblock (app->filemon, app->mfp_handler);
}
This allows the calls from the above two functions in menu_status_block_activate and menu_status_unblock_activate to work as intended and successfully block handling of the "changed" signal while blocked, and resume when unblocked. Why it cannot be done by direct call to g_signal_handler_block and g_signal_handler_unblock using the instance and handler_id will just have to remain a documentation mystery for the time being.
note: I'll leave the github.com gtktest code up until mid-April if anyone wants to play with it, thereafter the working code will exist at https://github.com/drankinatty/gtkwrite.

Registering a signal handler with wpa_supplicant p2p DBus interface

I'm running into issues trying to register to receive the "InvitationReceived" signal from wpa_supplicant's dbus interface for p2p using the gdbus library in C.
I can create a proxy connection to the P2P dbus interface just fine and call methods on it, but when I try to connect a signal handler to the proxy, I just get the following error saying the signal is invalid (the relevant output from the code sample):
(process:6764): GLib-GObject-WARNING **:
/tmp/buildd/glib2.0-2.42.1/./gobject/gsignal.c:2461: signal
'InvitationReceived' is invalid for instance '0x909ae0' of type
'GDBusProxy'
Which is weird, since "InvitationReceived" is the name of the signal as defined by the wpa_supplicant dbus api.
Code Sample:
static void on_wpa_ready (GObject *source_object,
GAsyncResult *res,
gpointer user_data) {
g_print("on_wpa_ready\n");
GError *error = NULL;
GVariant *output;
GDBusProxy *p2p_proxy = g_dbus_proxy_new_for_bus_finish(res, &error);
if (error) {
g_print("proxy finish error: %s\n", error->message);
g_error_free(error);
return;
}
/* call p2p_listen */
g_clear_error(&error);
output = NULL;
output = g_dbus_proxy_call_sync(p2p_proxy,
"Listen",
g_variant_new("(i)", 0), //params
G_DBUS_CALL_FLAGS_NONE,
10, //timeout_msec
NULL,
&error
);
if (error) {
g_print("Listen call error: %s\n", error->message);
g_error_free(error);
g_print("continuing...\n");
}
else {
/* it gets to this print stmt, so the method was able to be called */
g_print("Listen successful\n");
}
/* register for signal from p2p device */
/* THIS IS WHERE THE ERROR IS */
error = NULL;
g_signal_connect(p2p_proxy,
"InvitationReceived",
G_CALLBACK(on_signal), // stub func that does something simple
NULL);
}
int main (int argc, char **argv) {
GMainLoop *loop;
/* connect to wpa_supplicant p2p dbus interface */
g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
"fi.w1.wpa_supplicant1", //name,
"/fi/w1/wpa_supplicant1/Interfaces/0", //object_path,
"fi.w1.wpa_supplicant1.Interface.P2PDevice", //interface_name,
NULL,
on_wpa_ready, //callback,
NULL);
);
loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
}
Is there some special path that needs to be appended to the signal name? Or am I supposed to use a different proxy for registering signal handlers from the one used to call methods?
(Finally found the problem / a solution -- posting here for future gdbus users)
From the GIO documentation for GDBusProxy:
The generic “g-properties-changed” and “g-signal” signals are not very
convenient to work with. Therefore, the recommended way of working
with proxies is to subclass GDBusProxy, and have more natural
properties and signals in your derived class.
As this paragraph hints, it turns out that the base GDBusProxy class only supports the two generic signals that all interfaces are guaranteed to have: g-properties-changed and g-signal. Registering for the g-signal signal on a proxy invokes the callback whenever any signal is emitted by the object of the given proxy, including the one I happened to be looking for in this case.
Instead of going the subclassing route suggested in the documentation, I ended up just using a quick-and-dirty catchall handler:
// the new snippet for connecting a signal handler:
g_signal_connect(p2p_proxy,
"g-signal",
G_CALLBACK(on_signal), // stub func that does something simple
NULL);
And then checking for which signal was actually called in the callback function:
/* callback function */
static void on_signal (GDBusProxy *proxy,
gchar *sender_name,
gchar *signal_name,
GVariant *params,
gpointer user_data) {
if (g_strcmp0(signal_name, "InvitationReceived")) {
// ignore all irrelevant signals
return;
}
g_print("InvitationReceived signal received\n");
/* other handling code.... */
}

ARM cross compiled ZeroMQ zstr_rcv() gives segmentation fault

I cross-compiled zmq and czmq for ARM (arm-poky-linux) to build a PUB-SUB message router. In the program, I fork a attached thread using zthread_fork() and talk through the pipe. When I do a zstr_rcv() from main after forking, i get a segmentation fault. This code works fine in my Ubuntu box with GCC. What am I doing wrong here? or is it a ARM compatibility issue?
Below is a simple code snippet.
// listener thread function.
static void listener_thread (void *args, zctx_t *ctx, void *pipe)
{
// Send sync message to main().
zstr_send (pipe, "READY");
// Do work.
while (1)
{
sleep (1);
}
}
// main() forks the listener thread and waits for the sync message from the listener with zstr_rcv().
int main (int argc, char **argv)
{
// Create a ZeroMQ context.
zctx_t *context = zctx_new();
assert (context);
// Deploy the listner.
void *listener = zthread_fork (context, listener_thread, NULL);
assert (listener);
// Wait for the sync signal.
char *string = zstr_recv (listener);
zstr_free (&string);
// Do stuff here.
while (1)
{
sleep (1);
}
return 0;
}
From the manual:
// Receive C string from socket. Caller must free returned string using
// zstr_free(). Returns NULL if the context is being terminated or the
// process was interrupted.
CZMQ_EXPORT char *
zstr_recv (void *source);
Note how the suggestion is to use zstr_free() instead of free(). You might just be getting away with a bad behavior on your Ubuntu desktop by luck. Try the suggested freeing method and see if that works better
This was simply a case of mismatched library versions. Instead of the required libzmq.so.3 for czmq, I have used libzmq.so.4. Once the correct versions were used, everything was well.
On a brighter note, hope others will learn from this. Apologies for the confusion created.

signal callback and pthread sync

On my app I have a pthread running a while(1) that read a socket client and a serial callback function. My app receive messages from a serial (like /dev/ttyS0) and receive messages from socket. The problem: the app crash after receive some messages from serial, on this moment the socket is receiving nothing. But if I comment the thread creation the app work fine.
code draft:
// Socket Thread
static void *Socket(void *arg)
{
// socket inicialization
while (1)
{
ret = read(client, buffer, sizeof(buffer)-1);
// do something
}
}
// serial callback
static void SerialCallback(int id, unsigned char *buffer, int length)
{
// do something
}
// main
int main (void)
{
// start and configure serial callback
cssl_start();
Serial = cssl_open(SERIAL_PORT, SerialCallback, 0, 115200, 8, 0, 1);
// create the pthread
// If I comment the line below the app work fine
pthread_create(&Thread_Socket, NULL, Socket, NULL);
while (1)
{
}
}
Notes:
I use the library cssl (http://sourceforge.net/projects/cssl/) to deal with serial. This library use a real time signal.
For tests purposes I use socat to generate pseudo-terminals (like /dev/pts/XX)
The serial callback is called each time that serial receive one or more bytes
I am using the cutecom to send messages to serial
Added new tests information in 2012.07.16
First test: I replace the line of read function by a while(1); and the problem follow (so, the problem is not related with read function).
Second test: Using the full code (above example), I use two external usb/serial converter loopback connected, work rightly.
How said #Nikolai N Fetissov, the program break because EINTR signal. I looked into cssl library code and change the flags of signal, from: sa.sa_flags = SA_SIGINFO; to sa.sa_flags = SA_SIGINFO | SA_RESTART;. Worked.
I contacted Marcin Siennicki, cssl project developer, and sent the link of this post for him.
Thanks for comments.

Resources