~ubuntu-branches/ubuntu/natty/plymouth/natty

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
Origin: commit:5daa29168df38b8b5f0f59b0c65a5740082e002a
Author: Ray Strode <rstrode@redhat.com>
Subject: [event-loop] Add reference count to event sources

This prevents the event loop from freeing sources
early in an iteration of the loop, and then dispatching
handlers for the source later in that same iteration.

Index: b/src/libply/ply-event-loop.c
===================================================================
--- a/src/libply/ply-event-loop.c
+++ b/src/libply/ply-event-loop.c
@@ -56,6 +56,7 @@
   ply_list_t *fd_watches;
   uint32_t is_getting_polled : 1;
   uint32_t is_disconnected : 1;
+  int reference_count;
 } ply_event_source_t;
 
 typedef struct
@@ -319,6 +320,12 @@
   free (watch);
 }
 
+static void
+ply_event_source_take_reference (ply_event_source_t *source)
+{
+  source->reference_count++;
+}
+
 static ply_event_source_t *
 ply_event_source_new (int fd)
 {
@@ -331,6 +338,7 @@
   source->fd_watches = ply_list_new ();
   source->is_getting_polled = false;
   source->is_disconnected = false;
+  source->reference_count = 0;
 
   return source;
 }
@@ -349,6 +357,22 @@
 }
 
 static void
+ply_event_source_drop_reference (ply_event_source_t *source)
+{
+  if (source == NULL)
+    return;
+
+  source->reference_count--;
+
+  assert (source->reference_count >= 0);
+
+  if (source->reference_count == 0)
+    {
+      ply_event_source_free (source);
+    }
+}
+
+static void
 ply_event_loop_update_source_event_mask (ply_event_loop_t   *loop,
                                          ply_event_source_t *source)
 {
@@ -404,6 +428,7 @@
   assert (source != NULL);
 
   destination->source = source;
+  ply_event_source_take_reference (source);
   destination_node = ply_list_append_data (source->destinations, destination);
   assert (destination_node != NULL);
   assert (destination->source == source);
@@ -412,6 +437,7 @@
 
   watch = ply_fd_watch_new (destination);
 
+  ply_event_source_take_reference (source);
   ply_list_append_data (source->fd_watches, watch);
 
   return watch;
@@ -449,6 +475,7 @@
   assert (source != NULL);
 
   ply_list_remove_data (source->destinations, destination);
+  ply_event_source_drop_reference (source);
   assert (ply_list_find_node (source->destinations, destination) == NULL);
   ply_event_loop_update_source_event_mask (loop, source);
 }
@@ -601,6 +628,7 @@
 
   source->is_getting_polled = true;
 
+  ply_event_source_take_reference (source);
   ply_list_append_data (loop->sources, source);
 }
 
@@ -622,6 +650,7 @@
     }
 
   ply_list_remove_node (loop->sources, source_node);
+  ply_event_source_drop_reference (source);
 }
 
 static void
@@ -749,6 +778,7 @@
     {
       ply_trace ("source for fd %d is already disconnected", source->fd);
       ply_list_remove_data (source->fd_watches, watch);
+      ply_event_source_drop_reference (source);
       ply_fd_watch_free (watch);
       return;
     }
@@ -757,6 +787,7 @@
   ply_event_loop_remove_destination_by_fd_watch (loop, watch);
 
   ply_list_remove_data (source->fd_watches, watch);
+  ply_event_source_drop_reference (source);
   ply_fd_watch_free (watch);
   ply_event_destination_free (destination);
 
@@ -764,8 +795,6 @@
     {
       ply_trace ("no more destinations remaing for fd %d, removing source", source->fd);
       ply_event_loop_remove_source (loop, source);
-      ply_trace ("freeing source for fd %d", source->fd);
-      ply_event_source_free (source);
     }
 }
 
@@ -1083,6 +1112,7 @@
       assert (watch != NULL);
       ply_fd_watch_free (watch);
       ply_list_remove_node (source->fd_watches, node);
+      ply_event_source_drop_reference (source);
       node = next_node;
     }
 }
@@ -1142,6 +1172,7 @@
       ply_event_destination_free (destination);
 
       ply_list_remove_node (source->destinations, node);
+      ply_event_source_drop_reference (source);
       node = next_node;
     }
 }
@@ -1169,9 +1200,6 @@
   ply_trace ("removing source with fd %d from event loop", source->fd);
   ply_event_loop_remove_source (loop, source);
   ply_trace ("done removing source with fd %d from event loop", source->fd);
-
-  ply_trace ("freeing source with fd %d", source->fd);
-  ply_event_source_free (source);
 }
 
 static void
@@ -1261,6 +1289,19 @@
     }
   while ((number_of_received_events < 0) && ((errno == EINTR) || (errno == EAGAIN)));
 
+  /* first reference all sources, so they stay alive for the duration of this
+   * iteration of the loop
+   */
+  for (i = 0; i < number_of_received_events; i++)
+    {
+      ply_event_source_t *source;
+      source = (ply_event_source_t *) (events[i].data.ptr);
+
+      ply_event_source_take_reference (source);
+    }
+
+  /* Then process the incoming events
+   */
   for (i = 0; i < number_of_received_events; i++)
     {
       ply_event_source_t *source;
@@ -1293,6 +1334,17 @@
       if (loop->should_exit)
         break;
     }
+
+  /* Finally, kill off any unused sources
+   */
+  for (i = 0; i < number_of_received_events; i++)
+    {
+      ply_event_source_t *source;
+
+      source = (ply_event_source_t *) (events[i].data.ptr);
+
+      ply_event_source_drop_reference (source);
+    }
 }
 
 void