parsav  Diff

Differences From Artifact [d1470e4b10]:

To Artifact [1565f096a3]:


   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