chiark / gitweb /
bus: stop using EDEADLOCK
[elogind.git] / src / libsystemd / sd-bus / bus-slot.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "sd-bus.h"
23 #include "bus-control.h"
24 #include "bus-objects.h"
25 #include "bus-slot.h"
26
27 sd_bus_slot *bus_slot_allocate(
28                 sd_bus *bus,
29                 bool floating,
30                 BusSlotType type,
31                 size_t extra,
32                 void *userdata) {
33
34         sd_bus_slot *slot;
35
36         assert(bus);
37
38         slot = malloc0(offsetof(sd_bus_slot, reply_callback) + extra);
39         if (!slot)
40                 return NULL;
41
42         slot->n_ref = 1;
43         slot->type = type;
44         slot->bus = bus;
45         slot->floating = floating;
46         slot->userdata = userdata;
47
48         if (!floating)
49                 sd_bus_ref(bus);
50
51         LIST_PREPEND(slots, bus->slots, slot);
52
53         return slot;
54 }
55
56 _public_ sd_bus_slot* sd_bus_slot_ref(sd_bus_slot *slot) {
57         assert_return(slot, NULL);
58
59         assert(slot->n_ref > 0);
60
61         slot->n_ref++;
62         return slot;
63 }
64
65 void bus_slot_disconnect(sd_bus_slot *slot) {
66         sd_bus *bus;
67
68         assert(slot);
69
70         if (!slot->bus)
71                 return;
72
73         switch (slot->type) {
74
75         case BUS_REPLY_CALLBACK:
76
77                 if (slot->reply_callback.cookie != 0)
78                         ordered_hashmap_remove(slot->bus->reply_callbacks, &slot->reply_callback.cookie);
79
80                 if (slot->reply_callback.timeout != 0)
81                         prioq_remove(slot->bus->reply_callbacks_prioq, &slot->reply_callback, &slot->reply_callback.prioq_idx);
82
83                 break;
84
85         case BUS_FILTER_CALLBACK:
86                 slot->bus->filter_callbacks_modified = true;
87                 LIST_REMOVE(callbacks, slot->bus->filter_callbacks, &slot->filter_callback);
88                 break;
89
90         case BUS_MATCH_CALLBACK:
91
92                 if (slot->bus->bus_client)
93                         bus_remove_match_internal(slot->bus, slot->match_callback.match_string, slot->match_callback.cookie);
94
95                 slot->bus->match_callbacks_modified = true;
96                 bus_match_remove(&slot->bus->match_callbacks, &slot->match_callback);
97
98                 free(slot->match_callback.match_string);
99
100                 break;
101
102         case BUS_NODE_CALLBACK:
103
104                 if (slot->node_callback.node) {
105                         LIST_REMOVE(callbacks, slot->node_callback.node->callbacks, &slot->node_callback);
106                         slot->bus->nodes_modified = true;
107
108                         bus_node_gc(slot->bus, slot->node_callback.node);
109                 }
110
111                 break;
112
113         case BUS_NODE_ENUMERATOR:
114
115                 if (slot->node_enumerator.node) {
116                         LIST_REMOVE(enumerators, slot->node_enumerator.node->enumerators, &slot->node_enumerator);
117                         slot->bus->nodes_modified = true;
118
119                         bus_node_gc(slot->bus, slot->node_enumerator.node);
120                 }
121
122                 break;
123
124         case BUS_NODE_OBJECT_MANAGER:
125
126                 if (slot->node_object_manager.node) {
127                         LIST_REMOVE(object_managers, slot->node_object_manager.node->object_managers, &slot->node_object_manager);
128                         slot->bus->nodes_modified = true;
129
130                         bus_node_gc(slot->bus, slot->node_object_manager.node);
131                 }
132
133                 break;
134
135         case BUS_NODE_VTABLE:
136
137                 if (slot->node_vtable.node && slot->node_vtable.interface && slot->node_vtable.vtable) {
138                         const sd_bus_vtable *v;
139
140                         for (v = slot->node_vtable.vtable; v->type != _SD_BUS_VTABLE_END; v++) {
141                                 struct vtable_member *x = NULL;
142
143                                 switch (v->type) {
144
145                                 case _SD_BUS_VTABLE_METHOD: {
146                                         struct vtable_member key;
147
148                                         key.path = slot->node_vtable.node->path;
149                                         key.interface = slot->node_vtable.interface;
150                                         key.member = v->x.method.member;
151
152                                         x = hashmap_remove(slot->bus->vtable_methods, &key);
153                                         break;
154                                 }
155
156                                 case _SD_BUS_VTABLE_PROPERTY:
157                                 case _SD_BUS_VTABLE_WRITABLE_PROPERTY: {
158                                         struct vtable_member key;
159
160                                         key.path = slot->node_vtable.node->path;
161                                         key.interface = slot->node_vtable.interface;
162                                         key.member = v->x.method.member;
163
164
165                                         x = hashmap_remove(slot->bus->vtable_properties, &key);
166                                         break;
167                                 }}
168
169                                 free(x);
170                         }
171                 }
172
173                 free(slot->node_vtable.interface);
174
175                 if (slot->node_vtable.node) {
176                         LIST_REMOVE(vtables, slot->node_vtable.node->vtables, &slot->node_vtable);
177                         slot->bus->nodes_modified = true;
178
179                         bus_node_gc(slot->bus, slot->node_vtable.node);
180                 }
181
182                 break;
183
184         default:
185                 assert_not_reached("Wut? Unknown slot type?");
186         }
187
188         bus = slot->bus;
189
190         slot->type = _BUS_SLOT_INVALID;
191         slot->bus = NULL;
192         LIST_REMOVE(slots, bus->slots, slot);
193
194         if (!slot->floating)
195                 sd_bus_unref(bus);
196 }
197
198 _public_ sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) {
199
200         if (!slot)
201                 return NULL;
202
203         assert(slot->n_ref > 0);
204
205         if (slot->n_ref > 1) {
206                 slot->n_ref --;
207                 return NULL;
208         }
209
210         bus_slot_disconnect(slot);
211         free(slot->description);
212         free(slot);
213
214         return NULL;
215 }
216
217 _public_ sd_bus* sd_bus_slot_get_bus(sd_bus_slot *slot) {
218         assert_return(slot, NULL);
219
220         return slot->bus;
221 }
222
223 _public_ void *sd_bus_slot_get_userdata(sd_bus_slot *slot) {
224         assert_return(slot, NULL);
225
226         return slot->userdata;
227 }
228
229 _public_ void *sd_bus_slot_set_userdata(sd_bus_slot *slot, void *userdata) {
230         void *ret;
231
232         assert_return(slot, NULL);
233
234         ret = slot->userdata;
235         slot->userdata = userdata;
236
237         return ret;
238 }
239
240 _public_ sd_bus_message *sd_bus_slot_get_current_message(sd_bus_slot *slot) {
241         assert_return(slot, NULL);
242         assert_return(slot->type >= 0, NULL);
243
244         if (slot->bus->current_slot != slot)
245                 return NULL;
246
247         return slot->bus->current_message;
248 }
249
250 _public_ sd_bus_message_handler_t sd_bus_slot_get_current_handler(sd_bus_slot *slot) {
251         assert_return(slot, NULL);
252         assert_return(slot->type >= 0, NULL);
253
254         if (slot->bus->current_slot != slot)
255                 return NULL;
256
257         return slot->bus->current_handler;
258 }
259
260 _public_ void* sd_bus_slot_get_current_userdata(sd_bus_slot *slot) {
261         assert_return(slot, NULL);
262         assert_return(slot->type >= 0, NULL);
263
264         if (slot->bus->current_slot != slot)
265                 return NULL;
266
267         return slot->bus->current_userdata;
268 }
269
270 _public_ int sd_bus_slot_set_description(sd_bus_slot *slot, const char *description) {
271         assert_return(slot, -EINVAL);
272
273         return free_and_strdup(&slot->description, description);
274 }
275
276 _public_ int sd_bus_slot_get_description(sd_bus_slot *slot, char **description) {
277         assert_return(slot, -EINVAL);
278         assert_return(description, -EINVAL);
279         assert_return(slot->description, -ENXIO);
280
281         *description = slot->description;
282         return 0;
283 }