1 /**
2  * ae.sys.process
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <ae@cy.md>
12  */
13 
14 module ae.sys.process;
15 
16 version (Posix)
17 {
18 	import core.sys.posix.unistd : getlogin;
19 	import std.process : environment;
20 	import std.string : fromStringz;
21 }
22 version (Windows)
23 {
24 	import core.sys.windows.lmcons : UNLEN;
25 	import core.sys.windows.winbase : GetUserNameW;
26 	import core.sys.windows.windef : DWORD;
27 	import core.sys.windows.winnt : WCHAR;
28 	import ae.sys.windows.exception : wenforce;
29 	import ae.sys.windows.text : fromWString;
30 }
31 
32 /// Get the name of the user that the current process is running under.
33 // Note: Windows does not have numeric user IDs, which is why this
34 // cross-platform function always returns a string.
35 string getCurrentUser()
36 {
37 	version (Posix)
38 		return environment.get("LOGNAME", cast(string)getlogin().fromStringz);
39 	version (Windows)
40 	{
41 		WCHAR[UNLEN + 1] buf;
42 		DWORD len = buf.length;
43 		GetUserNameW(buf.ptr, &len).wenforce("GetUserNameW");
44 		return buf[].fromWString();
45 	}
46 }
47 
48 version(Posix):
49 
50 import ae.net.sync;
51 import ae.sys.signals;
52 
53 import std.process;
54 
55 /// Asynchronously wait for a process to terminate.
56 void asyncWait(Pid pid, void delegate(int status) dg)
57 {
58 	auto anchor = new ThreadAnchor;
59 
60 	void handler() nothrow @nogc
61 	{
62 		anchor.runAsync(
63 			{
64 				// Linux may coalesce multiple SIGCHLD into one, so
65 				// we need to explicitly check if our process exited.
66 				auto result = tryWait(pid);
67 				if (result.terminated)
68 				{
69 					removeSignalHandler(SIGCHLD, &handler);
70 					dg(result.status);
71 				}
72 			});
73 	}
74 
75 	addSignalHandler(SIGCHLD, &handler);
76 }
77 
78 version(unittest) import ae.sys.timing, ae.net.asockets;
79 
80 unittest
81 {
82 	string order;
83 
84 	auto pid = spawnProcess(["sleep", "1"]);
85 	asyncWait(pid, (int status) { assert(status == 0); order ~= "b"; });
86 	setTimeout({ order ~= "a"; },  500.msecs);
87 	setTimeout({ order ~= "c"; }, 1500.msecs);
88 	socketManager.loop();
89 
90 	assert(order == "abc");
91 }