@@ -80,21 +80,55 @@ bool append_quoted(wchar_t* out, okw_uptr cap, okw_uptr& at, const wchar_t* s, o
8080
8181extern " 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
255266int 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
315310kal_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