~binli/ubuntu/vivid/pulseaudio/load-extcon-module

« back to all changes in this revision

Viewing changes to src/modules/reserve-monitor.c

  • Committer: Bin Li
  • Date: 2016-01-23 15:04:48 UTC
  • Revision ID: bin.li@canonical.com-20160123150448-5ockvw4p5xxntda4
init the 1:6.0-0ubuntu9.15 from silo 12

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: t -*-*/
 
2
 
 
3
/***
 
4
  Copyright 2009 Lennart Poettering
 
5
 
 
6
  Permission is hereby granted, free of charge, to any person
 
7
  obtaining a copy of this software and associated documentation files
 
8
  (the "Software"), to deal in the Software without restriction,
 
9
  including without limitation the rights to use, copy, modify, merge,
 
10
  publish, distribute, sublicense, and/or sell copies of the Software,
 
11
  and to permit persons to whom the Software is furnished to do so,
 
12
  subject to the following conditions:
 
13
 
 
14
  The above copyright notice and this permission notice shall be
 
15
  included in all copies or substantial portions of the Software.
 
16
 
 
17
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
18
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
19
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
20
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 
21
  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 
22
  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
23
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
24
  SOFTWARE.
 
25
***/
 
26
 
 
27
#include <string.h>
 
28
#include <unistd.h>
 
29
#include <errno.h>
 
30
#include <stdlib.h>
 
31
#include <stdio.h>
 
32
#include <assert.h>
 
33
 
 
34
#include "reserve-monitor.h"
 
35
#include "reserve.h"
 
36
 
 
37
struct rm_monitor {
 
38
        int ref;
 
39
 
 
40
        char *device_name;
 
41
        char *service_name;
 
42
        char *match;
 
43
 
 
44
        DBusConnection *connection;
 
45
 
 
46
        unsigned busy:1;
 
47
        unsigned filtering:1;
 
48
        unsigned matching:1;
 
49
 
 
50
        rm_change_cb_t change_cb;
 
51
        void *userdata;
 
52
};
 
53
 
 
54
#define SERVICE_PREFIX "org.freedesktop.ReserveDevice1."
 
55
 
 
56
#define SERVICE_FILTER                          \
 
57
        "type='signal',"                        \
 
58
        "sender='" DBUS_SERVICE_DBUS "',"       \
 
59
        "interface='" DBUS_INTERFACE_DBUS "',"  \
 
60
        "member='NameOwnerChanged',"            \
 
61
        "arg0='%s'"
 
62
 
 
63
static unsigned get_busy(
 
64
        DBusConnection *c,
 
65
        const char *name_owner) {
 
66
 
 
67
        const char *un;
 
68
 
 
69
        if (!name_owner || !*name_owner)
 
70
                return FALSE;
 
71
 
 
72
        /* If we ourselves own the device, then don't consider this 'busy' */
 
73
        if ((un = dbus_bus_get_unique_name(c)))
 
74
                if (strcmp(name_owner, un) == 0)
 
75
                        return FALSE;
 
76
 
 
77
        return TRUE;
 
78
}
 
79
 
 
80
static DBusHandlerResult filter_handler(
 
81
        DBusConnection *c,
 
82
        DBusMessage *s,
 
83
        void *userdata) {
 
84
 
 
85
        rm_monitor *m;
 
86
        DBusError error;
 
87
 
 
88
        dbus_error_init(&error);
 
89
 
 
90
        m = userdata;
 
91
        assert(m->ref >= 1);
 
92
 
 
93
        if (dbus_message_is_signal(s, "org.freedesktop.DBus", "NameOwnerChanged")) {
 
94
                const char *name, *old, *new;
 
95
 
 
96
                if (!dbus_message_get_args(
 
97
                            s,
 
98
                            &error,
 
99
                            DBUS_TYPE_STRING, &name,
 
100
                            DBUS_TYPE_STRING, &old,
 
101
                            DBUS_TYPE_STRING, &new,
 
102
                            DBUS_TYPE_INVALID))
 
103
                        goto invalid;
 
104
 
 
105
                if (strcmp(name, m->service_name) == 0) {
 
106
                        unsigned old_busy = m->busy;
 
107
 
 
108
                        m->busy = get_busy(c, new);
 
109
 
 
110
                        if (m->busy != old_busy && m->change_cb) {
 
111
                                m->ref++;
 
112
                                m->change_cb(m);
 
113
                                rm_release(m);
 
114
                        }
 
115
                }
 
116
        }
 
117
 
 
118
invalid:
 
119
        dbus_error_free(&error);
 
120
 
 
121
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
122
}
 
123
 
 
124
int rm_watch(
 
125
        rm_monitor **_m,
 
126
        DBusConnection *connection,
 
127
        const char *device_name,
 
128
        rm_change_cb_t change_cb,
 
129
        DBusError *error)  {
 
130
 
 
131
        rm_monitor *m = NULL;
 
132
        char *name_owner;
 
133
        int r;
 
134
        DBusError _error;
 
135
 
 
136
        if (!error)
 
137
                error = &_error;
 
138
 
 
139
        dbus_error_init(error);
 
140
 
 
141
        if (!_m)
 
142
                return -EINVAL;
 
143
 
 
144
        if (!connection)
 
145
                return -EINVAL;
 
146
 
 
147
        if (!device_name)
 
148
                return -EINVAL;
 
149
 
 
150
        if (!(m = calloc(sizeof(rm_monitor), 1)))
 
151
                return -ENOMEM;
 
152
 
 
153
        m->ref = 1;
 
154
 
 
155
        if (!(m->device_name = strdup(device_name))) {
 
156
                r = -ENOMEM;
 
157
                goto fail;
 
158
        }
 
159
 
 
160
        m->connection = dbus_connection_ref(connection);
 
161
        m->change_cb = change_cb;
 
162
 
 
163
        if (!(m->service_name = malloc(sizeof(SERVICE_PREFIX) + strlen(device_name)))) {
 
164
                r = -ENOMEM;
 
165
                goto fail;
 
166
        }
 
167
        sprintf(m->service_name, SERVICE_PREFIX "%s", m->device_name);
 
168
 
 
169
        if (!(dbus_connection_add_filter(m->connection, filter_handler, m, NULL))) {
 
170
                r = -ENOMEM;
 
171
                goto fail;
 
172
        }
 
173
 
 
174
        m->filtering = 1;
 
175
 
 
176
        if (!(m->match = malloc(sizeof(SERVICE_FILTER) - 2 + strlen(m->service_name)))) {
 
177
                r = -ENOMEM;
 
178
                goto fail;
 
179
        }
 
180
 
 
181
        sprintf(m->match, SERVICE_FILTER, m->service_name);
 
182
        dbus_bus_add_match(m->connection, m->match, error);
 
183
 
 
184
        if (dbus_error_is_set(error)) {
 
185
                r = -EIO;
 
186
                goto fail;
 
187
        }
 
188
 
 
189
        m->matching = 1;
 
190
 
 
191
        if ((r = rd_dbus_get_name_owner(m->connection, m->service_name, &name_owner, error)) < 0)
 
192
                goto fail;
 
193
 
 
194
        m->busy = get_busy(m->connection, name_owner);
 
195
        free(name_owner);
 
196
 
 
197
        *_m = m;
 
198
        return 0;
 
199
 
 
200
fail:
 
201
        if (&_error == error)
 
202
                dbus_error_free(&_error);
 
203
 
 
204
        if (m)
 
205
                rm_release(m);
 
206
 
 
207
        return r;
 
208
}
 
209
 
 
210
void rm_release(rm_monitor *m) {
 
211
        if (!m)
 
212
                return;
 
213
 
 
214
        assert(m->ref > 0);
 
215
 
 
216
        if (--m->ref > 0)
 
217
                return;
 
218
 
 
219
        if (m->matching)
 
220
                dbus_bus_remove_match(
 
221
                        m->connection,
 
222
                        m->match,
 
223
                        NULL);
 
224
 
 
225
        if (m->filtering)
 
226
                dbus_connection_remove_filter(
 
227
                        m->connection,
 
228
                        filter_handler,
 
229
                        m);
 
230
 
 
231
        free(m->device_name);
 
232
        free(m->service_name);
 
233
        free(m->match);
 
234
 
 
235
        if (m->connection)
 
236
                dbus_connection_unref(m->connection);
 
237
 
 
238
        free(m);
 
239
}
 
240
 
 
241
int rm_busy(rm_monitor *m) {
 
242
        if (!m)
 
243
                return -EINVAL;
 
244
 
 
245
        assert(m->ref > 0);
 
246
 
 
247
        return m->busy;
 
248
}
 
249
 
 
250
void rm_set_userdata(rm_monitor *m, void *userdata) {
 
251
 
 
252
        if (!m)
 
253
                return;
 
254
 
 
255
        assert(m->ref > 0);
 
256
        m->userdata = userdata;
 
257
}
 
258
 
 
259
void* rm_get_userdata(rm_monitor *m) {
 
260
 
 
261
        if (!m)
 
262
                return NULL;
 
263
 
 
264
        assert(m->ref > 0);
 
265
 
 
266
        return m->userdata;
 
267
}