Skip to content

Commit aababc6

Browse files
committed
0.6.0 --- one spawn, a working directory, and an honest refusal of the job
`CreateProcessW' has taken a current directory all along; what was missing until openkal 0.11 was a caller able to say which. It is now `how->work', obtained through the same `GetFinalPathNameByHandleW' the image path comes from. ⚠️⚠️ KAL_SPAWN_OWN_JOB IS REFUSED, AND NOT BECAUSE THIS SYSTEM CANNOT DO IT --- it is the system the idea comes from. A job object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE is exactly the unit the flag describes. What is missing is somewhere to keep the job: `kal_process' is one machine word and it holds the process handle, so `kal_process_terminate' could not reach the job later. The other two implementations need no storage because `getpgid(pid) == pid' recovers the fact from the kernel; this one has no equivalent. ⇒ Claiming it would mean a side table keyed by process handle, and a side table that is wrong under concurrency terminates the WRONG tree. Refused until it can be done without one --- a smaller lie than "kills sometimes". The three unclaimed positions and the calls that refuse them are now written together above kal_process_props, because a word claiming what the next call declines is the disagreement clause 6.2 exists to prevent.
1 parent abe7c11 commit aababc6

2 files changed

Lines changed: 55 additions & 60 deletions

File tree

mcpp.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
namespace = "mcpplibs"
33
name = "openkal-windows"
4-
version = "0.5.0"
4+
version = "0.6.0"
55
description = "An implementation of openkal for Windows, written on the Win32 interfaces and the object manager beneath them, using no C runtime symbol."
66
license = "Apache-2.0"
77

@@ -18,7 +18,7 @@ authors = ["mcpplibs"]
1818
repo = "https://github.com/mcpplibs/openkal-windows"
1919

2020
[dependencies]
21-
openkal = "0.10.0"
21+
openkal = "0.11.0"
2222

2323
# The package contributes definitions and no modules. The interface it
2424
# implements is declared by the specification package, which this package

src/process.cpp

Lines changed: 53 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -80,21 +80,55 @@ bool append_quoted(wchar_t* out, okw_uptr cap, okw_uptr& at, const wchar_t* s, o
8080

8181
extern "C" {
8282

83-
int kal_process_spawn(kal_dir base,
83+
// Starting a program. One function since openkal 0.11.
84+
//
85+
// ⚠️ TWO OF THE FIVE POSITIONS IN `kal_spawn' ARE REFUSED HERE, AND EACH REFUSAL
86+
// IS OLDER THAN 0.11 --- the record moved, the answers did not.
87+
//
88+
// `grants': this environment has no numbering a preopen could arrive under, so
89+
// there is no correspondence to descriptor three. KAL_PROCESS_PROP_GRANT_DIR is
90+
// not claimed. A count of zero asks for a program with no preopens, which is
91+
// what a program here gets anyway, so that request IS answerable and is
92+
// answered.
93+
//
94+
// `KAL_SPAWN_BOUND_LIFETIME': no primitive arms it from inside the started image.
95+
//
96+
// ⚠️⚠️ `KAL_SPAWN_OWN_JOB' IS REFUSED, AND NOT BECAUSE THIS SYSTEM CANNOT DO IT ---
97+
// a job object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE is exactly the unit the
98+
// flag describes, and this is the environment the idea comes from. What is
99+
// missing is somewhere to keep the job: `kal_process' is one machine word and it
100+
// holds the process handle, so `kal_process_terminate' would have no way to
101+
// reach the job later. The other two implementations need no such storage
102+
// because `getpgid(pid) == pid' recovers the fact from the kernel.
103+
//
104+
// ⇒ Claiming it would mean a side table keyed by process handle, and a side
105+
// table that is wrong under concurrency terminates the wrong tree. Refused
106+
// until it can be done without one, which is a smaller lie than "kills
107+
// sometimes". Clause 6.2: the position is not claimed and a caller that asks
108+
// first is told.
109+
int kal_process_spawn(const kal_spawn* how,
84110
const char* path, kal_uintptr path_len,
85111
const char** argv, const kal_uintptr* argv_lens, kal_uintptr argc,
86112
const char** envp, const kal_uintptr* envp_lens, kal_uintptr envc,
87113
const kal_spawn_streams* streams,
88114
kal_process* out) {
89-
void* dir = okw::unpack(base.h);
90-
if (!dir || out == nullptr) return kal_err_invalid;
115+
if (how == nullptr || out == nullptr) return kal_err_invalid;
116+
void* dir = okw::unpack(how->base.h);
117+
void* run = okw::unpack(how->work.h);
118+
if (!dir || !run) return kal_err_invalid;
91119
if (!okw::acceptable(path, path_len)) return kal_err_invalid;
120+
if (how->grant_count > 0) return kal_err_not_supported;
121+
if (how->flags != 0) return kal_err_not_supported;
92122

93123
// The directory's own name, and the program's beneath it.
94124
// Obtained rather than kept in static storage: static storage shared
95125
// between execution contexts would make two concurrent spawns one.
96126
struct scratch {
97127
wchar_t image[okw::kMaxName];
128+
// ⭐ THE DIRECTORY THE PROGRAM RUNS IN, WHICH IS NOT THE ONE IT IS NAMED
129+
// FROM. `CreateProcessW' has taken a current directory all along; what
130+
// was missing until 0.11 was a caller able to say which.
131+
wchar_t cwd[okw::kMaxName];
98132
wchar_t line[kCommandLine];
99133
wchar_t block[kCommandLine];
100134
};
@@ -118,6 +152,13 @@ int kal_process_spawn(kal_dir base,
118152
}
119153
image[at] = 0;
120154

155+
// The same enquiry the image path comes from, upon the other directory.
156+
wchar_t* cwd = work->cwd;
157+
const DWORD cn = GetFinalPathNameByHandleW(run, cwd, okw::kMaxName - 1,
158+
FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
159+
if (cn == 0 || cn >= okw::kMaxName - 1) return okw::translate_win32(GetLastError());
160+
cwd[cn] = 0;
161+
121162
// The vector, unaltered, including its first element.
122163
wchar_t* line = work->line;
123164
okw_uptr used = 0;
@@ -170,7 +211,7 @@ int kal_process_spawn(kal_dir base,
170211
const BOOL started = CreateProcessW(image, argc ? line : nullptr, nullptr, nullptr,
171212
inherit ? TRUE : FALSE,
172213
CREATE_UNICODE_ENVIRONMENT,
173-
envc ? block : nullptr, nullptr, &startup, &info);
214+
envc ? block : nullptr, cwd, &startup, &info);
174215
if (!started) return okw::translate_win32(GetLastError());
175216
CloseHandle(info.hThread);
176217
*out = kal_process{ okw::pack(info.hProcess) };
@@ -221,36 +262,6 @@ void kal_process_channel_close(kal_stream s) {
221262
CloseHandle(h);
222263
}
223264

224-
// Starting a program that receives exactly the directories named.
225-
//
226-
// ⚠️ NOT PROVIDED, AND THE REFUSAL IS THE HONEST ANSWER RATHER THAN A GAP. A
227-
// preopened directory is a handle a started program reads back through
228-
// kal_fs_preopen by NUMBER, and this environment has no numbering: a handle
229-
// crosses a spawn by being inheritable, and the started program learns of it
230-
// through a mechanism the parent has to arrange itself. There is no
231-
// correspondence here to descriptor three.
232-
//
233-
// Clause 6.2 is what makes the refusal conforming rather than a deviation: the
234-
// operation exists, reports kal_err_not_supported, and the property word does
235-
// not claim KAL_PROCESS_PROP_GRANT_DIR. A caller therefore learns from the word
236-
// what it would otherwise learn from a failed call.
237-
int kal_process_spawn_with(kal_dir base,
238-
const char* path, kal_uintptr path_len,
239-
const char** argv, const kal_uintptr* argv_lens, kal_uintptr argc,
240-
const char** envp, const kal_uintptr* envp_lens, kal_uintptr envc,
241-
const kal_spawn_streams* streams,
242-
const kal_preopen* grants, kal_uintptr grant_count,
243-
kal_process* out) {
244-
// A count of zero asks for a program with no preopens, which this
245-
// environment gives a started program anyway --- it has none to pass. That
246-
// request is therefore answerable, and is answered by the ordinary spawn.
247-
if (grant_count == 0)
248-
return kal_process_spawn(base, path, path_len,
249-
argv, argv_lens, argc,
250-
envp, envp_lens, envc, streams, out);
251-
(void)grants;
252-
return kal_err_not_supported;
253-
}
254265

255266
int kal_process_wait(kal_process p, int* status, int* terminated) {
256267
void* h = okw::unpack(p.h);
@@ -287,31 +298,15 @@ void kal_process_close(kal_process p) {
287298
if (h) { okw::retire(p.h); CloseHandle(h); }
288299
}
289300

290-
// KAL_PROCESS_PROP_GRANT_DIR is deliberately absent: kal_process_spawn_with
291-
// refuses a non-empty set of grants here, and a word claiming a facility the
292-
// next call refuses is the disagreement clause 6.2 exists to prevent.
293-
// Starting a program whose lifetime is bound to this one's. Version 0.10.
294-
//
295-
// ⚠️⚠️ REFUSED HERE, AND NOT BECAUSE THIS SYSTEM CANNOT --- IT CAN. A job object
296-
// with `JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE' ends every program in the job when
297-
// the last handle to it closes, which this system does when a process dies
298-
// however it dies. That is exactly the binding openkal describes.
301+
// ⚠️ THREE POSITIONS ARE DELIBERATELY ABSENT, AND EACH IS ABSENT BECAUSE THE
302+
// NEXT CALL REFUSES IT. A word claiming a facility the operation then declines is
303+
// the disagreement clause 6.2 exists to prevent, so the two are written together
304+
// and read together:
299305
//
300-
// ⚠️ IT IS NOT CLAIMED IN THIS RELEASE BECAUSE IT HAS NOT BEEN MEASURED HERE.
301-
// The one consumer that needs it composes `execve', and this system already
302-
// declines `openkal.space' --- so nothing on this system reaches the operation
303-
// today, and claiming a binding that has never been exercised is the shape of
304-
// answer openkal exists to refuse. It is the next thing this implementation
305-
// should do, and it is recorded as that rather than as an absence.
306-
//
307-
// A caller that asks `kal_process_props' first is told before it depends on it.
308-
int kal_process_spawn_bound(kal_dir, const char*, kal_uintptr,
309-
const char**, const kal_uintptr*, kal_uintptr,
310-
const char**, const kal_uintptr*, kal_uintptr,
311-
const kal_spawn_streams*, kal_process*) {
312-
return kal_err_not_supported;
313-
}
314-
306+
// GRANT_DIR kal_process_spawn refuses a non-empty `grants'
307+
// BOUND_LIFETIME no primitive arms it from inside the started image
308+
// OWN_JOB the job exists; somewhere to keep its handle does not ---
309+
// see the note above kal_process_spawn
315310
kal_uintptr kal_process_props(void) { return
316311
KAL_PROCESS_PROP_TERMINATE | KAL_PROCESS_PROP_STREAM_PASSING
317312
| KAL_PROCESS_PROP_EXIT_STATUS

0 commit comments

Comments
 (0)