~cpick/mongrel2/release

« back to all changes in this revision

Viewing changes to src/mongrel2.c

  • Committer: Chris Pick
  • Date: 2013-06-30 16:39:57 UTC
  • mfrom: (1106.1.15)
  • Revision ID: git-v1:ec39967acb6bc9867ed9b9dc3774304ca6b9c294
Merge tag 'v1.8.1' into debian

Hotfix for github issue 148

Show diffs side-by-side

added added

removed removed

Lines of Context:
44
44
#include "task/task.h"
45
45
#include "config/config.h"
46
46
#include "config/db.h"
47
 
#include "adt/list.h"
 
47
#include "adt/darray.h"
48
48
#include "unixy.h"
49
49
#include "mime.h"
50
50
#include "superpoll.h"
56
56
 
57
57
extern int RUNNING;
58
58
extern uint32_t THE_CURRENT_TIME_IS;
59
 
int RELOAD;
60
 
int MURDER;
 
59
int RELOAD = 0;
 
60
int MURDER = 0;
 
61
 
 
62
const int TICKER_TASK_STACK = 16 * 1024;
 
63
const int RELOAD_TASK_STACK = 100 * 1024;
 
64
 
 
65
struct ServerTask {
 
66
    bstring db_file;
 
67
    bstring server_id;
 
68
};
61
69
 
62
70
struct tagbstring PRIV_DIR = bsStatic("/");
63
71
 
64
 
Server *SERVER = NULL;
 
72
Task *RELOAD_TASK = NULL;
65
73
 
66
74
 
67
75
void terminate(int s)
68
76
{
69
77
    MURDER = s == SIGTERM;
 
78
 
70
79
    switch(s)
71
80
    {
72
81
        case SIGHUP:
73
 
            RELOAD = 1;
74
 
            RUNNING = 0;
75
 
            log_info("RELOAD REQUESTED, I'll do it on the next request.");
 
82
            if(!RELOAD) {
 
83
                RELOAD = 1;
 
84
                if(RELOAD_TASK) {
 
85
                    tasksignal(RELOAD_TASK, s);
 
86
                }
 
87
            }
76
88
            break;
77
89
        default:
78
90
            if(!RUNNING) {
81
93
            } else {
82
94
                RUNNING = 0;
83
95
                log_info("SHUTDOWN REQUESTED: %s", MURDER ? "MURDER" : "GRACEFUL (SIGINT again to EXIT NOW)");
84
 
                fdclose(SERVER->listen_fd);
 
96
                Server *srv = Server_queue_latest();
 
97
 
 
98
                if(srv != NULL) {
 
99
                    fdclose(srv->listen_fd);
 
100
                }
85
101
            }
86
102
            break;
87
103
    }
135
151
        check(srv->listen_fd >= 0, "Can't announce on TCP port %d", srv->port);
136
152
        check(fdnoblock(srv->listen_fd) == 0, "Failed to set listening port %d nonblocking.", srv->port);
137
153
    } else {
138
 
        srv->listen_fd = dup(old_srv->listen_fd);
139
 
        check(srv->listen_fd != -1, "Failed to dup the socket from the running server.");
140
 
        fdclose(old_srv->listen_fd);
 
154
        srv->listen_fd = old_srv->listen_fd;
141
155
    }
142
156
 
143
157
    check(Server_start_handlers(srv, old_srv) == 0, "Failed to start handlers.");
159
173
    int rc = Unixy_remove_dead_pidfile(pid_file);
160
174
    check(rc == 0, "Failed to remove the dead PID file: %s", bdata(pid_file));
161
175
    bdestroy(pid_file);
162
 
    
 
176
 
163
177
    return 0;
164
178
error:
165
179
    return -1;
167
181
 
168
182
void tickertask(void *v)
169
183
{
 
184
    (void)v;
 
185
 
170
186
    taskname("ticker");
171
187
 
172
188
    while(!task_was_signaled()) {
175
191
        int min_wait = Setting_get_int("limits.tick_timer", 10);
176
192
        taskdelay(min_wait * 1000);
177
193
 
178
 
        // don't bother if these are all 0
179
 
        int min_ping = Setting_get_int("limits.min_ping", DEFAULT_MIN_PING);
180
 
        int min_write_rate = Setting_get_int("limits.min_write_rate", DEFAULT_MIN_READ_RATE);
181
 
        int min_read_rate = Setting_get_int("limits.min_read_rate", DEFAULT_MIN_WRITE_RATE);
182
 
 
183
 
        if(min_ping > 0 || min_write_rate > 0 || min_read_rate > 0) {
184
 
            int cleared = Register_cleanout();
185
 
 
186
 
            if(cleared > 0) {
187
 
                log_warn("Timeout task killed %d tasks, waiting %d seconds for more.", cleared, min_wait);
188
 
            } else {
189
 
                debug("No connections timed out.");
 
194
        // avoid doing this during a reload attempt
 
195
        if(!RELOAD) {
 
196
            // don't bother if these are all 0
 
197
            int min_ping = Setting_get_int("limits.min_ping", DEFAULT_MIN_PING);
 
198
            int min_write_rate = Setting_get_int("limits.min_write_rate", DEFAULT_MIN_READ_RATE);
 
199
            int min_read_rate = Setting_get_int("limits.min_read_rate", DEFAULT_MIN_WRITE_RATE);
 
200
 
 
201
            if(min_ping > 0 || min_write_rate > 0 || min_read_rate > 0) {
 
202
                int cleared = Register_cleanout();
 
203
 
 
204
                if(cleared > 0) {
 
205
                    log_warn("Timeout task killed %d tasks, waiting %d seconds for more.", cleared, min_wait);
 
206
                } else {
 
207
                    debug("No connections timed out.");
 
208
                }
190
209
            }
 
210
 
 
211
            // do a server queue cleanup to get rid of dead servers
 
212
            Server_queue_cleanup();
191
213
        }
192
214
    }
193
215
}
194
216
 
 
217
 
195
218
int attempt_chroot_drop(Server *srv)
196
219
{
197
220
    int rc = 0;
198
221
 
199
222
    if(Unixy_chroot(srv->chroot) == 0) {
200
223
        log_info("All loaded up, time to turn into a server.");
201
 
 
202
 
        check(access("/run", F_OK) == 0, "/run directory doesn't exist in %s or isn't owned right.", bdata(srv->chroot));
203
 
        check(access("/tmp", F_OK) == 0, "/tmp directory doesn't exist in %s or isn't owned right.", bdata(srv->chroot));
 
224
        log_info("-- Starting " VERSION ". Copyright (C) Zed A. Shaw. Licensed BSD.\n");
 
225
        log_info("-- Look in %s for startup messages and errors.", bdata(srv->error_log));
204
226
 
205
227
        rc = Unixy_daemonize();
206
228
        check(rc == 0, "Failed to daemonize, looks like you're hosed.");
239
261
    return -1;
240
262
}
241
263
 
 
264
 
242
265
void final_setup()
243
266
{
244
267
    start_terminator();
245
268
    Server_init();
246
269
    bstring end_point = bfromcstr("inproc://access_log");
247
 
    Log_init(bstrcpy(SERVER->access_log), end_point);
 
270
    Server *srv = Server_queue_latest();
 
271
    Log_init(bstrcpy(srv->access_log), end_point);
 
272
    Control_port_start();
 
273
    taskdelay(500);
 
274
    log_info("-- " VERSION " Running. Copyright (C) Zed A. Shaw. Licensed BSD.");
248
275
}
249
276
 
250
277
 
251
278
 
252
279
Server *reload_server(Server *old_srv, const char *db_file, const char *server_uuid)
253
280
{
254
 
    RUNNING = 1;
255
 
 
256
281
    log_info("------------------------ RELOAD %s -----------------------------------", server_uuid);
257
282
    MIME_destroy();
258
283
    Setting_destroy();
296
321
    Setting_destroy();
297
322
    MIME_destroy();
298
323
 
299
 
    log_info("Removing pid file %s", bdata(srv->pid_file));
300
 
    rc = unlink((const char *)srv->pid_file->data);
301
 
    check(rc != -1, "Failed to unlink pid_file: %s", bdata(srv->pid_file));
302
 
 
303
 
    Server_destroy(srv);
 
324
    if(access((char *)srv->pid_file->data, F_OK) == 0) {
 
325
        log_info("Removing pid file %s", bdata(srv->pid_file));
 
326
        rc = unlink((const char *)srv->pid_file->data);
 
327
        check(rc != -1, "Failed to unlink pid_file: %s", bdata(srv->pid_file));
 
328
    }
 
329
 
 
330
    rc = Server_queue_destroy();
 
331
    check(rc == 0, "Failed cleaning up the server run queue.");
 
332
 
 
333
    Register_destroy();
 
334
    fdshutdown();
304
335
 
305
336
    taskexitall(0);
306
337
error:
307
338
    taskexitall(1);
308
339
}
309
340
 
310
 
const int TICKER_TASK_STACK = 16 * 1024;
 
341
 
 
342
void reload_task(void *data)
 
343
{
 
344
    RELOAD_TASK = taskself();
 
345
    struct ServerTask *srv = data;
 
346
 
 
347
    while(1) {
 
348
        taskswitch();
 
349
        task_clear_signal();
 
350
 
 
351
        if(RELOAD) {
 
352
            log_info("Reload requested, will load %s from %s", bdata(srv->db_file), bdata(srv->server_id));
 
353
            Server *old_srv = Server_queue_latest();
 
354
            Server *new_srv = reload_server(old_srv, bdata(srv->db_file), bdata(srv->server_id));
 
355
            check(new_srv, "Failed to load the new configuration, exiting.");
 
356
 
 
357
            // for this to work handlers need to die more gracefully
 
358
            Server_queue_push(new_srv);
 
359
        } else {
 
360
            log_info("Shutdown requested, goodbye.");
 
361
            break;
 
362
        }
 
363
    }
 
364
 
 
365
    taskexit(0);
 
366
error:
 
367
    taskexit(1);
 
368
}
311
369
 
312
370
void taskmain(int argc, char **argv)
313
371
{
314
372
    dbg_set_log(stderr);
315
373
    int rc = 0;
316
374
 
317
 
    check(argc == 3 || argc == 4, "usage: mongrel2 config.sqlite server_uuid [config_module.so]");
 
375
    check(argc == 3 || argc == 4, "usage: %s config.sqlite server_uuid [config_module.so]", m2program);
318
376
 
319
377
    if(argc == 4) {
320
 
        log_info("Using configuration module %s to load configs.",
321
 
                argv[3]);
 
378
        log_info("Using configuration module %s to load configs.", argv[3]);
322
379
        rc = Config_module_load(argv[3]);
323
380
        check(rc != -1, "Failed to load the config module: %s", argv[3]);
324
381
    }
325
382
 
326
 
    SERVER = load_server(argv[1], argv[2], NULL);
327
 
    check(SERVER, "Aborting since can't load server.");
 
383
    Server_queue_init();
 
384
 
 
385
    Server *srv = load_server(argv[1], argv[2], NULL);
 
386
    check(srv != NULL, "Aborting since can't load server.");
 
387
    Server_queue_push(srv);
328
388
 
329
389
    SuperPoll_get_max_fd();
330
390
 
331
 
    rc = clear_pid_file(SERVER);
 
391
    rc = clear_pid_file(srv);
332
392
    check(rc == 0, "PID file failure, aborting rather than trying to start.");
333
393
 
334
 
    rc = attempt_chroot_drop(SERVER);
 
394
    rc = attempt_chroot_drop(srv);
335
395
    check(rc == 0, "Major failure in chroot/droppriv, aborting."); 
336
396
 
337
397
    final_setup();
338
398
 
339
 
    Control_port_start();
340
399
    taskcreate(tickertask, NULL, TICKER_TASK_STACK);
341
400
 
342
 
    while(1) {
343
 
        log_info("Starting " VERSION ". Copyright (C) Zed A. Shaw. Licensed BSD.");
344
 
        Server_start(SERVER);
345
 
 
346
 
        if(RELOAD) {
347
 
            log_info("Reload requested, will load %s from %s", argv[2], argv[1]);
348
 
            Server *new_srv = reload_server(SERVER, argv[1], argv[2]);
349
 
            check(new_srv, "Failed to load the new configuration, exiting.");
350
 
 
351
 
            // for this to work handlers need to die more gracefully
352
 
            SERVER = new_srv;
353
 
        } else {
354
 
            log_info("Shutdown requested, goodbye.");
355
 
            break;
356
 
        }
357
 
    }
358
 
 
359
 
    complete_shutdown(SERVER);
 
401
    struct ServerTask *srv_data = calloc(1, sizeof(struct ServerTask));
 
402
    srv_data->db_file = bfromcstr(argv[1]);
 
403
    srv_data->server_id = bfromcstr(argv[2]);
 
404
 
 
405
    taskcreate(reload_task, srv_data, RELOAD_TASK_STACK);
 
406
 
 
407
    rc = Server_run();
 
408
    check(rc != -1, "Server had a failure and exited early.");
 
409
    log_info("Server run exited, goodbye.");
 
410
 
 
411
    srv = Server_queue_latest();
 
412
    complete_shutdown(srv);
 
413
 
360
414
    return;
361
415
 
362
416
error: