From e4607f9f65d25f07bd822922243f99c43b247634 Mon Sep 17 00:00:00 2001 From: Yorhel Date: Fri, 21 Sep 2012 12:00:09 +0200 Subject: Initial commit of some experiments --- .gitignore | 21 +++++++ Makefile.am | 38 +++++++++++++ configure.in | 24 ++++++++ deps/fetch.sh | 13 +++++ src/global.h | 52 ++++++++++++++++++ src/interfaces.itf | 27 +++++++++ src/itf2h.pl | 146 +++++++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 478 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile.am create mode 100644 configure.in create mode 100644 deps/fetch.sh create mode 100644 src/global.h create mode 100644 src/interfaces.itf create mode 100755 src/itf2h.pl create mode 100644 src/main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fce4573 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +Makefile +Makefile.in +aclocal.m4 +autom4te.cache/ +config.log +config.status +config.h +config.h.in +configure +depcomp +.dirstamp +.deps/ +install-sh +missing +stamp-h1 +*~ +*.o +*.a +deps/ev +src/interfaces.h +dbustest diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..a9194ab --- /dev/null +++ b/Makefile.am @@ -0,0 +1,38 @@ +EXTRA_DIST= +noinst_LIBRARIES= +CFLAGS+=-I$(top_srcdir)/deps/ev + + +# libev +noinst_LIBRARIES+=libev.a +libev_a_SOURCES=deps/ev/ev.c +EXTRA_DIST+=\ + deps/ev/LICENSE\ + deps/ev/ev_epoll.c\ + deps/ev/ev.h\ + deps/ev/ev_kqueue.c\ + deps/ev/ev_poll.c\ + deps/ev/ev_port.c\ + deps/ev/ev_select.c\ + deps/ev/ev_vars.h\ + deps/ev/ev_wrap.h + + +# dbustest +bin_PROGRAMS=dbustest +dbustest_CPPFLAGS=$(DBUS_CFLAGS) +dbustest_LDADD=libev.a -lm $(DBUS_LIBS) +dbustest_SOURCES=\ + src/main.c + +noinst_HEADERSS=\ + src/global.h + +MOSTLYCLEANFILES=src/interfaces.h +EXTRA_DIST+=itf2h.pl src/interfaces.itf + +$(dbustest_OBJECTS): src/interfaces.h + +src/interfaces.h: $(srcdir)/src/itf2h.pl $(srcdir)/src/interfaces.itf + $(AM_V_GEN)$(srcdir)/src/itf2h.pl <$(srcdir)/src/interfaces.itf >src/interfaces.h + diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..a5b8b13 --- /dev/null +++ b/configure.in @@ -0,0 +1,24 @@ + +AC_INIT([bdustest],[0.1],[projects@yorhel.nl]) +AC_CONFIG_SRCDIR([.]) +AC_CONFIG_HEADER([config.h]) +AM_INIT_AUTOMAKE([foreign subdir-objects]) +PKG_PROG_PKG_CONFIG([0.18]) + +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_RANLIB + +AC_SYS_LARGEFILE + +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_DEFINE(EV_COMPAT3, 0, [Define to disable compatibility with pre-4.0 libev.]) +AC_DEFINE(EV_MULTIPLICITY, 0, [Define to disable support for multiple event loops.]) +m4_include([deps/ev/libev.m4]) + +PKG_CHECK_MODULES([DBUS], [dbus-1]) + + +AC_OUTPUT([Makefile]) + diff --git a/deps/fetch.sh b/deps/fetch.sh new file mode 100644 index 0000000..17e8d1d --- /dev/null +++ b/deps/fetch.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +ev() { + d=libev-4.11 + rm -rf ev\ + && wget http://dist.schmorp.de/libev/Attic/$d.tar.gz\ + && tar -xzf $d.tar.gz\ + && rm $d.tar.gz\ + && mv $d ev +} + +ev + diff --git a/src/global.h b/src/global.h new file mode 100644 index 0000000..5a44160 --- /dev/null +++ b/src/global.h @@ -0,0 +1,52 @@ + +#include "config.h" + +#include +#include + +/* Global dbus connection (defined in main.c) */ +extern DBusConnection *dbuscon; + + + +/* Interface structures */ + +#define ITFF_DEPRECATED 1 /* Methods, signals, properties */ +#define ITFF_NOREPLY 2 /* Methods */ +#define ITFF_READ 4 /* Properties */ +#define ITFF_WRITE 8 /* Properties */ +#define ITFF_READWRITE (ITFF_READ|ITFF_WRITE) +#define ITFF_EMITNONE 16 /* Properties: EmitsChangedSignal = false */ +#define ITFF_EMITCHANGE 32 /* Properties: EmitsChangedSignal = invalidates */ + + +typedef struct { + const char *name; + char flags; /* deprecated, noreply */ + char **in; + char **out; +} itf_method_t; + + +typedef struct { + const char *name; + char flags; /* deprecated */ + char **args; +} itf_signal_t; + + +typedef struct { + const char *name; + const char *type; + char flags; /* read,write,deprecated,emitnone,emitchange */ +} itf_property_t; + + +typedef struct { + const char *name; + int n_methods, n_signals, n_properties; + itf_method_t *methods; + itf_signal_t *signals; + itf_property_t *properties; +} itf_t; + diff --git a/src/interfaces.itf b/src/interfaces.itf new file mode 100644 index 0000000..e8a32ac --- /dev/null +++ b/src/interfaces.itf @@ -0,0 +1,27 @@ + +props org.freedesktop.DBus.Properties + + -- methods + + # Blah Blah useful stuff for POD documentation. + Set [noreply,deprecated] + in s interface_name + in s property_name + in v value + + Get + in s interface_name + in s property_name + out v value + + -- signals + + PropertiesChanged + s interface_name + a{sv} changed_properties + as invalidated_properties + + -- properties + + s ShmDirectory read,deprecated + diff --git a/src/itf2h.pl b/src/itf2h.pl new file mode 100755 index 0000000..9ebce65 --- /dev/null +++ b/src/itf2h.pl @@ -0,0 +1,146 @@ +#!/usr/bin/perl + +use strict; +use warnings; + + +# itf1 => { name, comment, methods, signals, properties }, ... +# methods = [ { name, comment, flags, in => [ [ type, name ], .. ], out }, .. ] +# signals = [ { name, comment, args => [ [ type, name ], .. ] }, .. ] +# properties = [ { type, name, comment }, .. ] +sub read_itf { + my %itf; + my $itf; + my $comment = ''; + my $sect; + + while(<>) { + chomp; + s/[\s\t]+/ /g; + s/ $//; + next if !$_; + + # Comment + if(/^ *#(.+)$/) { + $comment = "\n" if !$comment; + $comment .= $1; + next; + } + + # New interface + if(/^([^ ]+) ([^ ]+)$/) { + $itf = $1; + $itf{$itf} = { name => $2, comment => $comment, map +($_=>[]), qw|methods signals properties| }; + $comment = ''; + $sect = ''; + next; + } + die "Unknown directive or not in an interface: $_\n" if !$itf; + + # Section switcher + if(/^ -- (methods|signals|properties)$/) { + $sect = $1; + next; + } + die "Unknown directive or not in a section: $_\n" if !$sect; + + # Method start + if($sect eq 'methods' && /^ ([^ ]+)(?: \[([^ ]+)\])?$/) { + push @{$itf{$itf}{methods}}, { name => $1, comment => $comment, flags => $2, in => [], out => [] }; + $comment = ''; + next; + } + + # Method arg + if($sect eq 'methods' && /^ (in|out) ([^ ]+) ([^ ]+)$/) { + die "Argument before method name: $_\n" if !@{$itf{$itf}{methods}}; + push @{$itf{$itf}{methods}[$#{$itf{$itf}{methods}}]{$1}}, [ $2, $3 ]; + next; + } + + # Signal start + if($sect eq 'signals' && /^ ([^ ]+)(?: \[([^ ]+)\])?$/) { + push @{$itf{$itf}{signals}}, { name => $1, comment => $comment, flags => $2, args => [] }; + $comment = ''; + next; + } + + # Signal arg + if($sect eq 'signals' && /^ ([^ ]+) ([^ ]+)$/) { + die "Argument before signal name: $_\n" if !@{$itf{$itf}{signals}}; + push @{$itf{$itf}{signals}[$#{$itf{$itf}{signals}}]{args}}, [ $1, $2 ]; + next; + } + + # Properties + if($sect eq 'properties' && /^ ([^ ]+) ([^ ]+) ([^ ]+)$/) { + push @{$itf{$itf}{properties}}, { type => $1, name => $2, flags => $3, comment => $comment }; + $comment = ''; + next; + } + + die "Unknown directive: $_\n"; + } + + return %itf; +} + + +sub write_h { + my %itf = @_; + + my $argl = sub { + my($n, $a) = @_; + printf "static char *_itf_%s[] = {\n\t", $n; + print join ', ', map(qq{"$_->[0]", "$_->[1]"}, @$a), 'NULL'; + print "\n};\n"; + }; + + my $flags = sub { + my $f = shift->{flags}||''; + return join '|', 0, map $f=~/$_/?("ITFF_\U$_"):(), qw|deprecated noreply read write emitnone emitchange|; + }; + + print "/* File automatically generated by itf2h.pl, DO NOT EDIT. */\n\n"; + for my $itf (keys %itf) { + printf "\n#if !defined(ITF_IMPL_%s) && !defined(ITF_IMPL_ALL)\n", $itf; + printf "extern itf_t *itf_%s;\n", $itf; + printf "#else\n\n", $itf; + + # Method arguments + for my $m (@{$itf{$itf}{methods}}) { + $argl->(sprintf("%s_%s_%s", $itf, $m->{name}, $_), $m->{$_}) for ('in', 'out'); + } + + # Method list + printf "\nstatic itf_method_t _itf_%s_methods[] = {", $itf; + print join ",", map sprintf("\n\t".'{"%2$s", %3$s, _itf_%1$s_%2$s_in, _itf_%1$s_%2$s_out}', $itf, $_->{name}, $flags->($_)), @{$itf{$itf}{methods}}; + print "\n};\n\n"; + + # Signal arguments + $argl->(sprintf("%s_%s_args", $itf, $_->{name}), $_->{args}) for (@{$itf{$itf}{signals}}); + + # Signal list + printf "\nstatic itf_signal_t _itf_%s_signals[] = {", $itf; + print join ",", map sprintf("\n\t".'{"%2$s", %3$s, _itf_%1$s_%2$s_args}', $itf, $_->{name}, $flags->($_)), @{$itf{$itf}{signals}}; + print "\n};\n"; + + # Properties + printf "\nstatic itf_property_t _itf_%s_properties[] = {", $itf; + print join ",", map sprintf("\n\t".'{"%s", "%s", %s}', $_->{name}, $_->{type}, $flags->($_)), @{$itf{$itf}{properties}}; + print "\n};\n\n"; + + # The interface object + printf "itf_t _itf_%s = {\n", $itf; + printf "\t\"%s\",\n", $itf{$itf}{name}; + printf "\t%d, %d, %d,\n", scalar @{$itf{$itf}{methods}}, scalar @{$itf{$itf}{signals}}, scalar @{$itf{$itf}{properties}}; + printf "\t".'_itf_%s_methods, _itf_%1$s_signals, _itf_%1$s_properties'."\n", $itf; + print "};\n"; + printf "itf_t *itf_%s = &_itf_%1\$s;\n\n", $itf; + + printf "#endif /* ITF_IMPL_%s */\n\n", $itf; + } +} + +my %interfaces = read_itf; +write_h(%interfaces); diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..ba9ebed --- /dev/null +++ b/src/main.c @@ -0,0 +1,157 @@ +#include "global.h" + +#include +#include + + +DBusConnection *dbuscon; + +#define BUS_NAME "net.blicky.dbustest" + + + +/* dbus <-> libev IO watchers */ + +struct dbusev_io { ev_io io; DBusWatch *w; }; + +static void dbusev_io(ev_io *io, int revents) { + printf("io f=%d\n", revents); + dbus_watch_handle(((struct dbusev_io *)io)->w, (revents & EV_READ ? DBUS_WATCH_READABLE : 0) | (revents & EV_WRITE ? DBUS_WATCH_WRITABLE : 0)); +} + + +static void dbusev_watchtoggle(DBusWatch *w, void *data) { + printf("watchtoggle en=%d, fd=%d, f=%d\n", dbus_watch_get_enabled(w), dbus_watch_get_unix_fd(w), dbus_watch_get_flags(w)); + ev_io *io = dbus_watch_get_data(w); + if(dbus_watch_get_enabled(w)) { + int f = dbus_watch_get_flags(w); + ev_io_set(io, dbus_watch_get_unix_fd(w), (f & DBUS_WATCH_READABLE ? EV_READ : 0) | (f & DBUS_WATCH_WRITABLE ? EV_WRITE : 0)); + ev_io_start(io); + } else + ev_io_stop(io); +} + + +static dbus_bool_t dbusev_addwatch(DBusWatch *w, void *data) { + printf("addwatch\n"); + ev_io *io = malloc(sizeof(struct dbusev_io)); + if(!io) + return FALSE; + ((struct dbusev_io *)io)->w = w; + dbus_watch_set_data(w, io, NULL); + ev_init(io, dbusev_io); + dbusev_watchtoggle(w, data); + return TRUE; +} + + +static void dbusev_removewatch(DBusWatch *w, void *data) { + printf("removewatch\n"); + ev_io *io = dbus_watch_get_data(w); + ev_io_stop(io); + free(io); +} + + + +/* dbus <-> libev timeout functions */ + +struct dbusev_timer { ev_timer timer; DBusTimeout *t; }; + +static void dbusev_timer(ev_timer *timer, int revents) { + dbus_timeout_handle(((struct dbusev_timer *)timer)->t); +} + + +static void dbusev_timeouttoggle(DBusTimeout *t, void *data) { + printf("timeouttoggle\n"); + ev_timer *timer = dbus_timeout_get_data(t); + if(dbus_timeout_get_enabled(t)) { + timer->repeat = ((ev_tstamp)dbus_timeout_get_interval(t))/1000.0; + ev_timer_again(timer); + } else + ev_timer_stop(timer); +} + + +static dbus_bool_t dbusev_addtimeout(DBusTimeout *t, void *data) { + printf("addtimeout\n"); + ev_timer *timer = malloc(sizeof(struct dbusev_timer)); + if(!timer) + return FALSE; + ((struct dbusev_timer *)timer)->t = t; + dbus_timeout_set_data(t, timer, NULL); + ev_init(timer, dbusev_timer); + dbusev_timeouttoggle(t, data); + return TRUE; +} + + +static void dbusev_removetimeout(DBusTimeout *t, void *data) { + printf("removetimeout\n"); + ev_timer *timer = dbus_timeout_get_data(t); + ev_timer_stop(timer); + free(timer); +} + + + +/* dbus <-> libev dispatch handling */ + +static void dbusev_dispatch(ev_idle *idl, int revents) { + if(dbus_connection_dispatch(dbuscon) == DBUS_DISPATCH_COMPLETE) + ev_idle_stop(idl); +} + + +static void dbusev_dispatchstatus(DBusConnection *con, DBusDispatchStatus s, void *data) { + printf("dispatchstatus = %d\n", s); + static ev_idle *idl = NULL; + if(!idl) { + idl = malloc(sizeof(ev_idle)); + ev_idle_init(idl, dbusev_dispatch); + } + ev_idle_start(idl); +} + + + +/* Creates a dbus connection, requests (or rather, requires) our BUS_NAME and + * sets the connection up for use with libev. Exits on error. */ +static void init_dbus() { + DBusError err; + dbus_error_init(&err); + + dbuscon = dbus_bus_get(DBUS_BUS_STARTER, &err); + if(dbus_error_is_set(&err)) { + printf("Failed to connect to the bus: %s\n", err.message); + exit(1); + } + + int ret = dbus_bus_request_name(dbuscon, BUS_NAME, DBUS_NAME_FLAG_DO_NOT_QUEUE, &err); + if(dbus_error_is_set(&err) || ret == DBUS_REQUEST_NAME_REPLY_EXISTS) { + printf("Failed to acquire dbus name: %s\n", dbus_error_is_set(&err) ? err.message : "Name already taken"); + exit(1); + } + + dbus_connection_set_watch_functions(dbuscon, dbusev_addwatch, dbusev_removewatch, dbusev_watchtoggle, NULL, NULL); + dbus_connection_set_timeout_functions(dbuscon, dbusev_addtimeout, dbusev_removetimeout, dbusev_timeouttoggle, NULL, NULL); + dbus_connection_set_dispatch_status_function(dbuscon, dbusev_dispatchstatus, NULL, NULL); +} + + + +int main(int argc, char **argv) { + ev_default_loop(0); + init_dbus(); + + /* Make sure to dispatch() before entering the main loop, we may have missed + * a dispatchstatus update while initializing. */ + while(dbus_connection_dispatch(dbuscon) != DBUS_DISPATCH_COMPLETE) + ; + + ev_run(0); + + return 0; +} + -- cgit v1.2.3