~upstart-devel/upstart/trunk

« back to all changes in this revision

Viewing changes to util/telinit.c

mergeĀ lp:~vorlon/upstart/upstart-fix-racy-tests

Show diffs side-by-side

added added

removed removed

Lines of Context:
160
160
int
161
161
restart_upstart (void)
162
162
{
163
 
        nih_local NihDBusProxy *upstart = NULL;
164
 
        DBusPendingCall        *ret;
 
163
        nih_local NihDBusProxy  *upstart = NULL;
 
164
        NihError                *err;
 
165
        int                      ret;
165
166
 
166
167
        upstart = upstart_open (NULL);
167
168
        if (! upstart)
168
169
                return -1;
169
170
 
170
 
        /* Fire and forget:
171
 
         *
172
 
         * Ask Upstart to restart itself using the async interface to
173
 
         * avoid the client-side complaining if and when it detects that
174
 
         * Upstart has severed all connections to perform the re-exec.
175
 
         */
176
 
        ret = upstart_restart (upstart, NULL, NULL, NULL, 0);
177
 
        dbus_connection_flush(upstart->connection);
178
 
 
179
 
        /* We don't care about the return code, but we have to keep
180
 
         * the compiler happy.
181
 
         */
182
 
        if (ret != (DBusPendingCall *)TRUE)
183
 
                return 0;
 
171
        /* Ask Upstart to restart itself.
 
172
         *
 
173
         * Since it is not possible to serialise a D-Bus connection,
 
174
         * Upstart is forced to sever all D-Bus client connections,
 
175
         * including this one.
 
176
         *
 
177
         * Further, since the user expects telinit to block _until the
 
178
         * re-exec has finished and Upstart is accepting connections
 
179
         * once again_, the only solution is to wait for the forced
 
180
         * disconnect, then poll until it is possible to create a new
 
181
         * connection.
 
182
         *
 
183
         * Note that we don't (can't) care about the return code since
 
184
         * it's not reliable:
 
185
         *
 
186
         * - either the re-exec request completed and D-Bus returned zero
 
187
         *   before Upstart started the re-exec.
 
188
         *
 
189
         * - or the re-exec request completed but upstart started the
 
190
         *   re-exec (severing all D-Bus connections) before D-Bus got a
 
191
         *   chance to finish cleanly meaning we receive a return of -1.
 
192
         *
 
193
         * We cannot know exactly what happened so have to allow for
 
194
         * both scenarios. Note the implicit assumption that the re-exec
 
195
         * request itself was accepted. If this assumption is incorrect
 
196
         * (should not be possible), the worst case scenario is that
 
197
         * upstart does not re-exec and then we quickly drop out of the
 
198
         * reconnect block since it never went offline.
 
199
         */
 
200
        ret = upstart_restart_sync (NULL, upstart);
 
201
 
 
202
        if (ret < 0) {
 
203
                err = nih_error_get ();
 
204
                nih_free (err);
 
205
        }
 
206
 
 
207
        nih_free (upstart);
 
208
 
 
209
        nih_debug ("Waiting for upstart to finish re-exec");
 
210
 
 
211
        /* We believe Upstart is now in the process of
 
212
         * re-exec'ing so attempt forever to reconnect.
 
213
         *
 
214
         * This sounds dangerous but there is no other option,
 
215
         * and a connection must be possible unless the system
 
216
         * is completely broken.
 
217
         */
 
218
        while (TRUE) {
 
219
 
 
220
                upstart = upstart_open (NULL);
 
221
                if (upstart)
 
222
                        break;
 
223
 
 
224
                err = nih_error_get ();
 
225
                nih_free (err);
 
226
 
 
227
                /* Avoid DoS'ing the system whilst we wait */
 
228
                usleep (100000);
 
229
        }
184
230
 
185
231
        return 0;
186
232
}