aboutsummaryrefslogtreecommitdiffstats
path: root/src/location-geoclue2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/location-geoclue2.c')
-rw-r--r--src/location-geoclue2.c134
1 files changed, 66 insertions, 68 deletions
diff --git a/src/location-geoclue2.c b/src/location-geoclue2.c
index b6238df..84ef6b4 100644
--- a/src/location-geoclue2.c
+++ b/src/location-geoclue2.c
@@ -36,19 +36,23 @@
#define DBUS_ACCESS_ERROR "org.freedesktop.DBus.Error.AccessDenied"
+struct location_data {
+ struct location location;
+ int available;
+ int error;
+};
+
struct location_state {
GMainLoop *loop;
GThread *thread;
- GMutex lock;
int pipe_fd_read;
int pipe_fd_write;
- int available;
- int error;
- struct location location;
+ struct location_data data;
+ struct location_data saved_data;
};
-/* Print the message explaining denial from GeoClue. */
+/* Print the message explaining denial from GeoClue */
static void
print_denial_message(void)
{
@@ -60,15 +64,18 @@ print_denial_message(void)
"information.\n"));
}
-/* Indicate an unrecoverable error during GeoClue2 communication. */
static void
-mark_error(struct location_state *state)
+send_data(struct location_state *state)
{
- g_mutex_lock(&state->lock);
- state->error = 1;
- g_mutex_unlock(&state->lock);
+ while (write(state->pipe_fd_write, &state->data, sizeof(state->data)) == -1 && errno == EINTR);
+}
- write(state->pipe_fd_write, "", 1);
+/* Indicate an unrecoverable error during GeoClue2 communication */
+static void
+mark_error(struct location_state *state)
+{
+ state->data.error = 1;
+ send_data(state);
}
/* Handle position change callbacks */
@@ -102,26 +109,19 @@ geoclue_client_signal_cb(GDBusProxy *client, gchar *sender_name, gchar *signal_n
return;
}
- g_mutex_lock(&state->lock);
-
/* Read location properties */
lat_v = g_dbus_proxy_get_cached_property(location, "Latitude");
- state->location.latitude = g_variant_get_double(lat_v);
-
+ state->data.location.latitude = g_variant_get_double(lat_v);
lon_v = g_dbus_proxy_get_cached_property(location, "Longitude");
- state->location.longitude = g_variant_get_double(lon_v);
+ state->data.location.longitude = g_variant_get_double(lon_v);
+ state->data.available = 1;
- state->available = 1;
-
- g_mutex_unlock(&state->lock);
-
- write(state->pipe_fd_write, "", 1);
+ send_data(state);
}
/* Callback when GeoClue name appears on the bus */
static void
-on_name_appeared(GDBusConnection *conn, const gchar *name,
- const gchar *name_owner, gpointer user_data)
+on_name_appeared(GDBusConnection *conn, const gchar *name, const gchar *name_owner, gpointer user_data)
{
struct location_state *state = user_data;
const gchar *client_path;
@@ -239,14 +239,11 @@ on_name_vanished(GDBusConnection *connection, const gchar *name, gpointer user_d
(void) connection;
(void) name;
- g_mutex_lock(&state->lock);
- state->available = 0;
- g_mutex_unlock(&state->lock);
-
- write(state->pipe_fd_write, "", 1);
+ state->data.available = 0;
+ send_data(state);
}
-/* Callback when the pipe to the main thread is closed. */
+/* Callback when the pipe to the main thread is closed */
static gboolean
on_pipe_closed(GIOChannel *channel, GIOCondition condition, gpointer user_data)
{
@@ -259,7 +256,7 @@ on_pipe_closed(GIOChannel *channel, GIOCondition condition, gpointer user_data)
}
-/* Run loop for location provider thread. */
+/* Run loop for location provider thread */
static void *
run_geoclue2_loop(void *state_)
{
@@ -298,29 +295,30 @@ run_geoclue2_loop(void *state_)
}
static int
-location_geoclue2_init(struct location_state **state)
+geoclue2_create(struct location_state **state_out)
{
#if !GLIB_CHECK_VERSION(2, 35, 0)
g_type_init();
#endif
- *state = emalloc(sizeof(**state));
+ *state_out = emalloc(sizeof(**state_out));
return 0;
}
static int
-location_geoclue2_start(struct location_state *state)
+geoclue2_start(struct location_state *state)
{
int pipefds[2];
state->pipe_fd_read = -1;
state->pipe_fd_write = -1;
- state->available = 0;
- state->error = 0;
- state->location.latitude = 0;
- state->location.longitude = 0;
+ state->data.available = 0;
+ state->data.error = 0;
+ state->data.location.latitude = 0;
+ state->data.location.longitude = 0;
+ state->saved_data = state->data;
- if (pipe_nonblock(pipefds)) {
+ if (pipe_rdnonblock(pipefds)) {
weprintf(_("Failed to start GeoClue2 provider!"));
return -1;
}
@@ -328,37 +326,35 @@ location_geoclue2_start(struct location_state *state)
state->pipe_fd_read = pipefds[0];
state->pipe_fd_write = pipefds[1];
- write(state->pipe_fd_write, "", 1);
+ send_data(state); /* TODO why? */
- g_mutex_init(&state->lock);
state->thread = g_thread_new("geoclue2", run_geoclue2_loop, state);
return 0;
}
static void
-location_geoclue2_free(struct location_state *state)
+geoclue2_free(struct location_state *state)
{
- if (state->pipe_fd_read != -1)
+ if (state->pipe_fd_read >= 0)
close(state->pipe_fd_read);
- /* Closing the pipe should cause the thread to exit. */
+ /* Closing the pipe should cause the thread to exit */
g_thread_join(state->thread);
state->thread = NULL;
- g_mutex_clear(&state->lock);
free(state);
}
static void
-location_geoclue2_print_help(FILE *f)
+geoclue2_print_help(FILE *f)
{
fputs(_("Use the location as discovered by a GeoClue2 provider.\n"), f);
fputs("\n", f);
}
static int
-location_geoclue2_set_option(struct location_state *state, const char *key, const char *value)
+geoclue2_set_option(struct location_state *state, const char *key, const char *value)
{
(void) state;
(void) value;
@@ -367,35 +363,37 @@ location_geoclue2_set_option(struct location_state *state, const char *key, cons
}
static int
-location_geoclue2_get_fd(struct location_state *state)
+geoclue2_get_fd(struct location_state *state)
{
return state->pipe_fd_read;
}
static int
-location_geoclue2_handle(struct location_state *state, struct location *location, int *available)
+geoclue2_fetch(struct location_state *state, struct location *location_out, int *available_out)
{
- int error;
-
- read(state->pipe_fd_read, &(char){0}, 1);
-
- g_mutex_lock(&state->lock);
- error = state->error;
- *location = state->location;
- *available = state->available;
- g_mutex_unlock(&state->lock);
+ struct location_data data;
+ ssize_t r;
+
+ for (;;) {
+ r = read(state->pipe_fd_read, &data, sizeof(data));
+ if (r == (ssize_t)sizeof(data)) {
+ state->saved_data = data;
+ } else if (r > 0) {
+ /* writes of 512 bytes or less are always atomic on pipes */
+ weprintf("read <pipe>: %s", _("Unexpected message size"));
+ } else if (!r || errno == EAGAIN) {
+ break;
+ } else if (errno != EINTR) {
+ weprintf("read <pipe>:");
+ state->saved_data.error = 1;
+ break;
+ }
+ }
- return error ? -1 : 0;
+ *location_out = state->saved_data.location;
+ *available_out = state->saved_data.available;
+ return state->saved_data.error ? -1 : 0;
}
-const struct location_provider geoclue2_location_provider = {
- "geoclue2",
- &location_geoclue2_init,
- &location_geoclue2_start,
- &location_geoclue2_free,
- &location_geoclue2_print_help,
- &location_geoclue2_set_option,
- &location_geoclue2_get_fd,
- &location_geoclue2_handle
-};
+const struct location_provider geoclue2_location_provider = LOCATION_PROVIDER_INIT("geoclue2", geoclue2);