Differences From
Artifact [d1470e4b10]:
124 124 local q = quote
125 125 var [val]
126 126 [exp]
127 127 in val end
128 128 return q
129 129 end);
130 130 proc = {
131 + fork = terralib.externfunction('fork', {} -> int);
132 + daemonize = terralib.externfunction('daemon', {int,int} -> {});
131 133 exit = terralib.externfunction('exit', int -> {});
132 134 getenv = terralib.externfunction('getenv', rawstring -> rawstring);
135 + exec = terralib.externfunction('execv', {rawstring,&rawstring} -> int);
136 + execp = terralib.externfunction('execvp', {rawstring,&rawstring} -> int);
133 137 };
134 138 io = {
135 139 send = terralib.externfunction('write', {int, rawstring, intptr} -> ptrdiff);
136 140 recv = terralib.externfunction('read', {int, rawstring, intptr} -> ptrdiff);
141 + close = terralib.externfunction('close', {int} -> int);
137 142 say = macro(function(msg) return `lib.io.send(2, msg, [#(msg:asvalue())]) end);
138 143 fmt = terralib.externfunction('printf',
139 144 terralib.types.funcpointer({rawstring},{int},true));
140 145 };
141 146 str = { sz = terralib.externfunction('strlen', rawstring -> intptr) };
142 147 copy = function(tbl)
143 148 local new = {}
................................................................................
148 153 osclock = terralib.includec 'time.h';
149 154 }
150 155 if config.posix then
151 156 lib.uio = terralib.includec 'sys/uio.h';
152 157 lib.emit = lib.emitv -- use more efficient call where available
153 158 else lib.emit = lib.emit_unitary end
154 159
155 -local starttime = global(lib.osclock.time_t)
156 -local lastnoisetime = global(lib.osclock.time_t)
157 -local noise = global(uint8,1)
158 -local noise_header = function(code,txt,mod)
159 - if mod then
160 - return string.format('\27[%s;1m(%s %s)\27[m ', code,mod,txt)
161 - else
162 - return string.format('\27[%s;1m(%s)\27[m ', code,txt)
163 - end
164 -end
160 +
161 +lib.noise = {
162 + level = global(uint8,1);
163 + starttime = global(lib.osclock.time_t);
164 + lasttime = global(lib.osclock.time_t);
165 + header = function(code,txt,mod)
166 + if mod then
167 + return string.format('\27[%s;1m(%s %s)\27[m ', code,mod,txt)
168 + else
169 + return string.format('\27[%s;1m(%s)\27[m ', code,txt)
170 + end
171 + end;
172 +}
165 173
166 174 local terra timehdr()
167 175 var now = lib.osclock.time(nil)
168 - var diff = now - lastnoisetime
176 + var diff = now - lib.noise.lasttime
169 177 if diff > 30 then -- print cur time
170 - lastnoisetime = now
178 + lib.noise.lasttime = now
171 179 var curtime: int8[26]
172 180 lib.osclock.ctime_r(&now, &curtime[0])
173 181 for i=0,26 do if curtime[i] == @'\n' then curtime[i] = 0 break end end -- :/
174 182 [ lib.emit(false, 2, '\27[1m[', `&curtime[0], ']\27[;36m\n +00 ') ]
175 183 else -- print time since last msg
176 184 var dfs = arrayof(int8, 0x30 + diff/10, 0x30 + diff%10, 0x20, 0)
177 185 [ lib.emit(false, 2, ' \27[36m+', `&dfs[0]) ]
................................................................................
182 190 if level >= 3 and config.debug == false then
183 191 return macro(function(...) return {} end)
184 192 end
185 193 return macro(function(...)
186 194 local fn = (...).filename
187 195 local ln = tostring((...).linenumber)
188 196 local dbgtag = string.format('\27[35m · \27[34m%s:\27[1m%s\27[m\n', fn,ln)
189 - local q = lib.emit(level < 3 and true or dbgtag, 2, noise_header(code,n), ...)
197 + local q = lib.emit(level < 3 and true or dbgtag, 2, lib.noise.header(code,n), ...)
190 198 return quote
191 199 --lib.io.fmt(['attempting to emit at ' .. fn..':'..ln.. '\n'])
192 - if noise >= level then timehdr(); [q] end end
200 + if lib.noise.level >= level then timehdr(); [q] end end
193 201 end);
194 202 end
203 +local terra final_cleanup :: {} -> {}
195 204 lib.dbg = defrep(3,'debug', '32')
196 205 lib.report = defrep(2,'info', '35')
197 206 lib.warn = defrep(1,'warn', '33')
198 207 lib.bail = macro(function(...)
199 - local q = lib.emit(true, 2, noise_header('31','fatal'), ...)
208 + local q = lib.emit(true, 2, lib.noise.header('31','fatal'), ...)
200 209 return quote
201 - timehdr(); [q]
210 + if lib.noise.level ~= 0 then
211 + timehdr(); [q]
212 + end
213 + final_cleanup()
202 214 lib.proc.exit(1)
203 215 end
204 216 end);
205 217 lib.stat = terralib.memoize(function(ty)
206 218 local n = struct {
207 219 ok: bool
208 220 union {
................................................................................
332 344 lib.pk = lib.loadlib('mbedtls','mbedtls/pk.h')
333 345 lib.md = lib.loadlib('mbedtls','mbedtls/md.h')
334 346 lib.b64 = lib.loadlib('mbedtls','mbedtls/base64.h')
335 347 lib.net = lib.loadlib('mongoose','mongoose.h')
336 348 lib.pq = lib.loadlib('libpq','libpq-fe.h')
337 349
338 350 lib.load {
339 - 'mem', 'math', 'str', 'file', 'crypt';
351 + 'mem', 'math', 'str', 'file', 'crypt', 'ipc';
340 352 'http', 'html', 'session', 'tpl', 'store';
341 353
342 354 'smackdown'; -- md-alike parser
343 355 }
344 356
345 357 local be = {}
346 358 for _, b in pairs(config.backends) do
................................................................................
393 405 }
394 406
395 407 do
396 408 local p = string.format('parsav: %s\nbuilt on %s\n', config.build.str, config.build.when)
397 409 terra version() lib.io.send(1, p, [#p]) end
398 410 end
399 411
400 -terra lib.noise_init(default_level: uint)
401 - starttime = lib.osclock.time(nil)
402 - lastnoisetime = 0
412 +terra lib.noise.init(default_level: uint)
413 + lib.noise.starttime = lib.osclock.time(nil)
414 + lib.noise.lasttime = 0
403 415 var n = lib.proc.getenv('parsav_noise')
404 416 if n ~= nil then
405 417 if n[0] >= 0x30 and n[0] <= 0x39 and n[1] == 0 then
406 - noise = n[0] - 0x30
418 + lib.noise.level = n[0] - 0x30
407 419 return
408 420 end
409 421 end
410 - noise = default_level
422 + lib.noise.level = default_level
411 423 end
412 424 lib.load{'mgtool'}
413 425
414 426 local options = lib.cmdparse {
415 427 version = {'V', 'display information about the binary build and exit'};
416 428 verbose = {'v', 'increase logging verbosity', inc=1};
417 429 quiet = {'q', 'do not print to standard out'};
418 430 help = {'h', 'display this list'};
419 431 backend_file = {'B', 'init from specified backend file', consume=1};
420 432 static_dir = {'S', 'directory with overrides for static content', consume=1};
421 433 builtin_data = {'D', 'do not load static content overrides at runtime under any circumstances'};
422 434 instance = {'i', 'set an instance name to make it easier to control multiple daemons', consume = 1};
435 + no_ipc = {'I', 'disable IPC'};
423 436 }
424 437
425 438
426 439 local static_setup = quote end
427 440 local mapin = quote end
428 441 local odir = symbol(rawstring)
429 442 local pathbuf = symbol(lib.str.acc)
................................................................................
461 474 end or quote return end
462 475 ] end
463 476
464 477 var [pathbuf] defer pathbuf:free()
465 478 pathbuf:compose(odir,'/')
466 479 [mapin]
467 480 end
481 +
482 +terra final_cleanup()
483 + lib.ipc.global_emperor:release()
484 +end
468 485
469 486 local terra entry_daemon(argc: int, argv: &rawstring): int
470 487 if argc < 1 then lib.bail('bad invocation!') end
471 488
472 - lib.noise_init(1)
489 + lib.noise.init(1)
473 490 [lib.init]
474 491
475 492 -- shut mongoose the fuck up
476 493 lib.net.mg_log_set_callback([terra(msg: &opaque, sz: int, u: &opaque) end], nil)
477 494 var srv: lib.srv.overlord
478 495
479 496 do var mode: options
................................................................................
480 497 mode:parse(argc,argv) defer mode:free()
481 498 static_init(&mode)
482 499 if mode.version then version() return 0 end
483 500 if mode.help then
484 501 [ lib.emit(true, 1, 'usage: ',`argv[0],' ', options.helptxt.flags, ' [<args>…]', options.helptxt.opts) ]
485 502 return 0
486 503 end
504 + if mode.quiet then lib.noise.level = 0 end
487 505 var cnf: rawstring
488 506 if mode.backend_file ~= nil
489 507 then cnf = @mode.backend_file
490 508 else cnf = lib.proc.getenv('parsav_backend_file')
491 509 end
492 - if cnf == nil then cnf = [config.prefix_conf .. "backend.conf"] end
510 + if cnf == nil then cnf = [config.prefix_conf .. "/backend.conf"] end
493 511
494 512 srv:setup(cnf)
513 + if argv[0][0] == @'-' and argv[0][1] == 0 then
514 + lib.ipc.notify_parent(lib.ipc.signals.state_success)
515 + argv[0] = 'parsav service daemon'
516 + end
495 517 srv:start(lib.trn(mode.instance ~= nil, @mode.instance, nil))
496 518 end
519 + lib.ipc.global_emperor = lib.ipc.emperor.mk(true) defer lib.ipc.global_emperor:release()
497 520
498 521 lib.report('listening for requests')
499 - while true do
522 + while lib.ipc.proc_active do
500 523 srv:poll()
524 + while true do
525 + var d: lib.ipc.demand
526 + lib.ipc.global_emperor:poll(&d)
527 + var a = lib.ipc.ack {success = true}
528 + if d.cmd == lib.ipc.cmd.none then break
529 + elseif d.cmd == lib.ipc.cmd.stop then
530 + lib.ipc.proc_active = false
531 + elseif d.cmd == lib.ipc.cmd.enumerate then
532 + if srv.id ~= nil then
533 + lib.str.ncpy(&a.iname[0], srv.id, [(`a.iname).tree.type.N])
534 + else a.iname[0] = 0 end
535 + elseif d.cmd == lib.ipc.cmd.chnoise then
536 + lib.noise.level = d.operand
537 + elseif d.cmd == lib.ipc.cmd.cfgrefresh then
538 + srv.cfg:free()
539 + srv.cfg:load()
540 + end
541 + d:ack(&lib.ipc.global_emperor, &a)
542 + end
501 543 end
502 544 srv:shutdown()
503 545
504 546 return 0
505 547 end
506 -
507 548
508 549 local bflag = function(long,short)
509 550 if short and util.has(buildopts, short) then return true end
510 551 if long and util.has(buildopts, long) then return true end
511 552 return false
512 553 end
513 554