Soletta™ Framework
Framework for making IoT devices

Full online documentation | C API Index
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sol-glib-integration.h
Go to the documentation of this file.
1 /*
2  * This file is part of the Soletta (TM) Project
3  *
4  * Copyright (C) 2015 Intel Corporation. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #include <glib.h>
33 #include <sol-mainloop.h>
34 #include <sol-log.h>
35 #include <sol-util.h>
36 #include <sol-vector.h>
37 
38 static gboolean
40 {
41  return FALSE;
42 }
43 
44 static gboolean
46 {
47  return FALSE;
48 }
49 
50 static gboolean
51 _sol_glib_integration_gsource_dispatch(GSource *source, GSourceFunc cb, gpointer user_data)
52 {
53  return TRUE;
54 }
55 
59 static GSourceFuncs _sol_glib_integration_gsource_funcs = {
63 };
64 
65 static gboolean
67 {
68  return TRUE;
69 }
70 
72  struct sol_fd *watch;
74  int fd;
75  gushort events;
76 };
77 
78 static void
80 {
81  sol_fd_del(h->watch);
82  free(h);
83 }
84 
86  GSource gsource;
88  GPollFD *fds;
89  gint n_fds;
90  gint n_poll;
91  gint timeout;
92  gint max_prio;
93 };
94 
95 static uint32_t
97 {
98  uint32_t sol_flags = 0;
99 
100  if (gpoll_events & G_IO_IN) sol_flags |= SOL_FD_FLAGS_IN;
101  if (gpoll_events & G_IO_OUT) sol_flags |= SOL_FD_FLAGS_OUT;
102  if (gpoll_events & G_IO_PRI) sol_flags |= SOL_FD_FLAGS_PRI;
103  if (gpoll_events & G_IO_ERR) sol_flags |= SOL_FD_FLAGS_ERR;
104  if (gpoll_events & G_IO_HUP) sol_flags |= SOL_FD_FLAGS_HUP;
105  if (gpoll_events & G_IO_NVAL) sol_flags |= SOL_FD_FLAGS_NVAL;
106 
107  return sol_flags;
108 }
109 
110 static gushort
112 {
113  gushort glib_flags = 0;
114 
115  if (sol_flags & SOL_FD_FLAGS_IN) glib_flags |= G_IO_IN;
116  if (sol_flags & SOL_FD_FLAGS_OUT) glib_flags |= G_IO_OUT;
117  if (sol_flags & SOL_FD_FLAGS_PRI) glib_flags |= G_IO_PRI;
118  if (sol_flags & SOL_FD_FLAGS_ERR) glib_flags |= G_IO_ERR;
119  if (sol_flags & SOL_FD_FLAGS_HUP) glib_flags |= G_IO_HUP;
120  if (sol_flags & SOL_FD_FLAGS_NVAL) glib_flags |= G_IO_NVAL;
121 
122  return glib_flags;
123 }
124 
125 static GPollFD *
127 {
128  gint i;
129 
130  for (i = 0; i < mdata->n_poll; i++) {
131  GPollFD *gpfd = mdata->fds + i;
132  if (gpfd->fd == fd)
133  return gpfd;
134  }
135 
136  return NULL;
137 }
138 
139 static struct _sol_glib_integration_fd_handler *
141 {
142  uint16_t i;
144 
145  SOL_PTR_VECTOR_FOREACH_IDX (&mdata->handlers, h, i) {
146  if (h->fd == fd)
147  return h;
148  }
149 
150  return NULL;
151 }
152 
153 static bool
154 _sol_glib_integration_on_source_fd(void *data, int fd, uint32_t active_flags)
155 {
157  GPollFD *gpfd = _sol_glib_integration_source_gpollfd_find(h->mdata, fd);
158 
159  SOL_NULL_CHECK(gpfd, true);
160  gpfd->revents = _sol_glib_integration_fd_flags_to_gpoll_events(active_flags);
161 
162  return true;
163 }
164 
165 static void
167 {
168  uint16_t i;
170 
171  // 1 - cleanup fd handlers that are not needed or changed
172  // Walk backwards so deletion doesn't impact the indices.
174  GPollFD *gpfd = _sol_glib_integration_source_gpollfd_find(mdata, h->fd);
175 
176  if (gpfd && gpfd->events == h->events)
177  continue;
178 
179  if (gpfd)
180  SOL_DBG("glib fd=%d, changed events %#x -> %#x", h->fd, h->events, gpfd->events);
181  else
182  SOL_DBG("glib fd=%d is not needed anymore", h->fd);
184  sol_ptr_vector_del(&mdata->handlers, i);
185  }
186 
187  // 2 - create fd handlers for new or changed fds
188  for (i = 0; i < (uint16_t)mdata->n_poll; i++) {
189  const GPollFD *gpfd = mdata->fds + i;
190  uint32_t flags;
191  int r;
192 
194  if (h)
195  continue;
196 
197  h = (struct _sol_glib_integration_fd_handler *)malloc(sizeof(struct _sol_glib_integration_fd_handler));
198  SOL_NULL_CHECK(h);
199 
200  h->fd = gpfd->fd;
201  h->events = gpfd->events;
202  h->mdata = mdata;
203 
205 
206  h->watch = sol_fd_add(gpfd->fd,
208  SOL_NULL_CHECK_GOTO(h->watch, watch_failed);
209 
210  r = sol_ptr_vector_append(&mdata->handlers, h);
211  SOL_INT_CHECK_GOTO(r, < 0, append_failed);
212 
213  SOL_DBG("glib fd=%d monitoring events %#x", h->fd, h->events);
214  continue;
215 
216 append_failed:
217  sol_fd_del(h->watch);
218 watch_failed:
219  free(h);
220  return;
221  }
222 }
223 
224 static bool
226 {
227  GMainContext *ctx = g_source_get_context(&mdata->gsource);
228  gboolean r = g_main_context_acquire(ctx);
229 
230  /* NOTE: not doing wait() here, should we? */
231  if (!r)
232  SOL_WRN("couldn't acquire glib's context.");
233 
234  return r;
235 }
236 
237 static void
239 {
240  GMainContext *ctx = g_source_get_context(&mdata->gsource);
241 
242  g_main_context_release(ctx);
243 }
244 
245 static inline unsigned int
247 {
248  unsigned int left_zeros;
249 
250  if (u == 1)
251  return 1;
252  if ((left_zeros = __builtin_clz(u - 1)) < 1)
253  return 0;
254  return 1 << ((sizeof(u) * 8) - left_zeros);
255 }
256 
257 static bool
259 {
260  struct _sol_glib_integration_source_data *mdata =
261  (struct _sol_glib_integration_source_data *)data;
262  GMainContext *ctx = g_source_get_context(&mdata->gsource);
263  bool ready;
264  gint req_n_fds;
265 
267  return false;
268 
269  ready = g_main_context_prepare(ctx, &mdata->max_prio);
270 
271  /* NOTE: this shouldn't require a loop, but gmain.c does it, so we mimic
272  * such behavior here.
273  */
274  do {
275  size_t byte_size;
276  void *tmp;
277  int r;
278 
279  mdata->n_poll = g_main_context_query(ctx,
280  mdata->max_prio, &mdata->timeout, mdata->fds, mdata->n_fds);
281  req_n_fds = _sol_glib_integration_align_power2(mdata->n_poll);
282 
283  if (req_n_fds == mdata->n_fds)
284  break;
285 
286  r = sol_util_size_mul(sizeof(GPollFD), req_n_fds, &byte_size);
287  SOL_INT_CHECK_GOTO(r, < 0, failed);
288 
289  tmp = realloc(mdata->fds, byte_size);
290  if (byte_size > 0) {
291  SOL_NULL_CHECK_GOTO(tmp, failed);
292  memset(tmp, 0, byte_size);
293  }
294 
295  mdata->fds = (GPollFD *)tmp;
296  mdata->n_fds = req_n_fds;
297  } while (1);
298 
300 
302 
303  return ready;
304 
305 failed:
307  return false;
308 }
309 
310 static bool
311 _sol_glib_integration_source_get_next_timeout(void *data, struct timespec *ts)
312 {
313  struct _sol_glib_integration_source_data *mdata =
314  (struct _sol_glib_integration_source_data *)data;
315 
316  if (mdata->timeout < 0)
317  return false;
318 
319  *ts = sol_util_timespec_from_msec(mdata->timeout);
320  return true;
321 }
322 
323 static bool
325 {
326  struct _sol_glib_integration_source_data *mdata =
327  (struct _sol_glib_integration_source_data *)data;
328  GMainContext *ctx = g_source_get_context(&mdata->gsource);
329  bool ready;
330 
332  return false;
333 
334  ready = g_main_context_check(ctx,
335  mdata->max_prio, mdata->fds, mdata->n_poll);
336 
338 
339  return ready;
340 }
341 
342 static void
344 {
345  struct _sol_glib_integration_source_data *mdata =
346  (struct _sol_glib_integration_source_data *)data;
347  GMainContext *ctx = g_source_get_context(&mdata->gsource);
348 
350  return;
351 
352  g_main_context_dispatch(ctx);
353 
355 }
356 
357 static void
359 {
360  struct _sol_glib_integration_source_data *mdata =
361  (struct _sol_glib_integration_source_data *)data;
362  GMainContext *ctx = g_source_get_context(&mdata->gsource);
363  uint16_t i;
365 
368  }
370 
371  free(mdata->fds);
372 
373  g_source_destroy(&mdata->gsource);
374  g_source_unref(&mdata->gsource);
375 
376  g_main_context_unref(ctx);
377 }
378 
383 #ifndef SOL_NO_API_VERSION
385 #endif
391 };
392 
393 static bool
395 {
396  GMainContext *ctx;
397  GSource *gsource;
398  struct sol_mainloop_source *msource;
399  struct _sol_glib_integration_source_data *mdata;
400  guint id;
401 
402  /* no need to integrate if we're called from glib */
403  if (g_main_depth()) {
404  SOL_DBG("already running with glib");
405  return true;
406  }
407 
408  ctx = g_main_context_default();
409 
410  /* convention: we add a GSource with 'sol_init' as user_data to
411  * mark Soletta was integrated with Glib.
412  *
413  * it is a dummy gsource that does nothing other than exist to hold
414  * this mark.
415  */
416  gsource = g_main_context_find_source_by_user_data(ctx, (void *)sol_init);
417  if (gsource)
418  return true;
419 
420  gsource = g_source_new(&_sol_glib_integration_gsource_funcs,
421  sizeof(struct _sol_glib_integration_source_data));
422  SOL_NULL_CHECK(gsource, false);
423  g_source_set_callback(gsource,
425 
426  id = g_source_attach(gsource, ctx);
427  SOL_INT_CHECK_GOTO(id, == 0, failed_gsource);
428 
429  mdata = (struct _sol_glib_integration_source_data *)gsource;
430  sol_ptr_vector_init(&mdata->handlers);
431  mdata->fds = NULL;
432  mdata->n_fds = 0;
433  mdata->n_poll = 0;
434  mdata->timeout = -1;
435  mdata->max_prio = 0;
436 
437  msource = sol_mainloop_add_source(&_sol_glib_integration_source_type, gsource);
438  SOL_NULL_CHECK_GOTO(msource, failed_mainloop_source);
439 
440  g_main_context_ref(ctx);
441  SOL_DBG("glib's mainloop is now integrated");
442 
443  return true;
444 
445 failed_mainloop_source:
446  g_source_destroy(gsource);
447 failed_gsource:
448  g_source_unref(gsource);
449  SOL_WRN("failed to integrate glib's mainloop");
450  return false;
451 }
static GSourceFuncs _sol_glib_integration_gsource_funcs
Source callbacks needed for the integration of the mainloops.
Definition: sol-glib-integration.h:59
static struct _sol_glib_integration_fd_handler * _sol_glib_integration_source_fd_handler_data_find(struct _sol_glib_integration_source_data *mdata, int fd)
Definition: sol-glib-integration.h:140
uint16_t api_version
must match SOL_MAINLOOP_SOURCE_TYPE_API_VERSION at runtime.
Definition: sol-mainloop.h:673
#define SOL_DBG(fmt,...)
Logs a message with debug level.
Definition: sol-log.h:671
#define SOL_NULL_CHECK(ptr,...)
Convenience macro to check for NULL pointer.
Definition: sol-log.h:223
int sol_init(void)
Initializes the Soletta library.
static uint32_t _sol_glib_integration_gpoll_events_to_fd_flags(gushort gpoll_events)
Definition: sol-glib-integration.h:96
static bool _sol_glib_integration_source_get_next_timeout(void *data, struct timespec *ts)
Definition: sol-glib-integration.h:311
#define SOL_PTR_VECTOR_FOREACH_IDX(vector, itrvar, idx)
Macro to iterate over the pointer vector easily.
Definition: sol-vector.h:672
static void sol_ptr_vector_clear(struct sol_ptr_vector *pv)
Delete all elements from the vector.
Definition: sol-vector.h:642
static void _sol_glib_integration_source_fd_handlers_adjust(struct _sol_glib_integration_source_data *mdata)
Definition: sol-glib-integration.h:166
#define SOL_WRN(fmt,...)
Logs a message with warning level.
Definition: sol-log.h:645
gushort events
Definition: sol-glib-integration.h:75
gint max_prio
Definition: sol-glib-integration.h:92
int sol_util_size_mul(size_t op1, size_t op2, size_t *out)
Multiply two values checking for overflow.
Structure representing the type of a source of mainloop events.
Definition: sol-mainloop.h:667
static void _sol_glib_integration_source_dispose(void *data)
Definition: sol-glib-integration.h:358
Definition: sol-glib-integration.h:85
static unsigned int _sol_glib_integration_align_power2(unsigned int u)
Definition: sol-glib-integration.h:246
int fd
Definition: sol-glib-integration.h:74
GSource gsource
Definition: sol-glib-integration.h:86
static gboolean _sol_glib_integration_gsource_check(GSource *source)
Definition: sol-glib-integration.h:45
static const struct sol_mainloop_source_type _sol_glib_integration_source_type
Source type to integrate the mainloops (see sol_mainloop_source_type)
Definition: sol-glib-integration.h:382
Definition: sol-glib-integration.h:71
These routines are used for Soletta logging.
static bool sol_glib_integration(void)
Definition: sol-glib-integration.h:394
struct sol_ptr_vector handlers
Definition: sol-glib-integration.h:87
static gboolean _sol_glib_integration_gsource_dispatch(GSource *source, GSourceFunc cb, gpointer user_data)
Definition: sol-glib-integration.h:51
static bool _sol_glib_integration_source_acquire(struct _sol_glib_integration_source_data *mdata)
Definition: sol-glib-integration.h:225
static bool _sol_glib_integration_source_prepare(void *data)
Definition: sol-glib-integration.h:258
static bool _sol_glib_integration_source_check(void *data)
Definition: sol-glib-integration.h:324
static FILE * fd
Definition: download.c:28
static bool _sol_glib_integration_on_source_fd(void *data, int fd, uint32_t active_flags)
Definition: sol-glib-integration.h:154
static struct sol_timeout * timeout
Definition: browse.c:36
Useful general routines.
gint n_fds
Definition: sol-glib-integration.h:89
struct sol_mainloop_source sol_mainloop_source
Structure of a Source of mainloop events.
Definition: sol-mainloop.h:762
gint timeout
Definition: sol-glib-integration.h:91
static int sol_ptr_vector_del(struct sol_ptr_vector *pv, uint16_t i)
Remove the pointer of index i from the vector.
Definition: sol-vector.h:541
struct _sol_glib_integration_source_data * mdata
Definition: sol-glib-integration.h:73
static gushort _sol_glib_integration_fd_flags_to_gpoll_events(uint32_t sol_flags)
Definition: sol-glib-integration.h:111
static void _sol_glib_integration_fd_handler_del(struct _sol_glib_integration_fd_handler *h)
Definition: sol-glib-integration.h:79
struct sol_fd * watch
Definition: sol-glib-integration.h:72
static void sol_ptr_vector_init(struct sol_ptr_vector *pv)
Initializes a sol_ptr_vector structure.
Definition: sol-vector.h:326
static GPollFD * _sol_glib_integration_source_gpollfd_find(struct _sol_glib_integration_source_data *mdata, int fd)
Definition: sol-glib-integration.h:126
Soletta pointer vector is a wrapper around vector with an API more convenient to handle pointers...
Definition: sol-vector.h:310
static void _sol_glib_integration_source_release(struct _sol_glib_integration_source_data *mdata)
Definition: sol-glib-integration.h:238
#define SOL_NULL_CHECK_GOTO(ptr, label)
Convenience macro to check for NULL pointer and jump to a given label.
Definition: sol-log.h:262
static struct timespec sol_util_timespec_from_msec(int msec)
Create a struct timespec from milliseconds.
Definition: sol-util.h:195
#define SOL_PTR_VECTOR_FOREACH_REVERSE_IDX(vector, itrvar, idx)
Macro to iterate over the pointer vector easily in the reverse order.
Definition: sol-vector.h:701
These are routines that Soletta provides for its vector implementation.
static gboolean _sol_glib_integration_gsource_cb(gpointer user_data)
Definition: sol-glib-integration.h:66
#define SOL_INT_CHECK_GOTO(var, exp, label)
Similar to SOL_INT_CHECK but jumping to label instead of returning.
Definition: sol-log.h:345
#define SOL_MAINLOOP_SOURCE_TYPE_API_VERSION
Compile time API version to be checked during runtime.
Definition: sol-mainloop.h:669
GPollFD * fds
Definition: sol-glib-integration.h:88
gint n_poll
Definition: sol-glib-integration.h:90
struct sol_mainloop_source * sol_mainloop_add_source(const struct sol_mainloop_source_type *type, const void *data)
Create a new source of events to the main loop.
static gboolean _sol_glib_integration_gsource_prepare(GSource *source, gint *timeout)
Definition: sol-glib-integration.h:39
These routines are used for Soletta's mainloop manipulation.
int sol_ptr_vector_append(struct sol_ptr_vector *pv, const void *ptr)
Append a pointer to the end of the vector.
static void _sol_glib_integration_source_dispatch(void *data)
Definition: sol-glib-integration.h:343