Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
21f5597d
Commit
21f5597d
authored
May 18, 2021
by
Paul Gofman
Committed by
Alexandre Julliard
May 19, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
server: Support nested jobs.
Signed-off-by:
Paul Gofman
<
pgofman@codeweavers.com
>
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
d7ce5bdd
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
273 additions
and
32 deletions
+273
-32
process.c
dlls/kernel32/tests/process.c
+176
-2
process.c
server/process.c
+97
-30
No files found.
dlls/kernel32/tests/process.c
View file @
21f5597d
...
@@ -71,6 +71,7 @@ static BOOL (WINAPI *pQueryFullProcessImageNameA)(HANDLE hProcess, DWORD dwFla
...
@@ -71,6 +71,7 @@ static BOOL (WINAPI *pQueryFullProcessImageNameA)(HANDLE hProcess, DWORD dwFla
static
BOOL
(
WINAPI
*
pQueryFullProcessImageNameW
)(
HANDLE
hProcess
,
DWORD
dwFlags
,
LPWSTR
lpExeName
,
PDWORD
lpdwSize
);
static
BOOL
(
WINAPI
*
pQueryFullProcessImageNameW
)(
HANDLE
hProcess
,
DWORD
dwFlags
,
LPWSTR
lpExeName
,
PDWORD
lpdwSize
);
static
DWORD
(
WINAPI
*
pK32GetProcessImageFileNameA
)(
HANDLE
,
LPSTR
,
DWORD
);
static
DWORD
(
WINAPI
*
pK32GetProcessImageFileNameA
)(
HANDLE
,
LPSTR
,
DWORD
);
static
HANDLE
(
WINAPI
*
pCreateJobObjectW
)(
LPSECURITY_ATTRIBUTES
sa
,
LPCWSTR
name
);
static
HANDLE
(
WINAPI
*
pCreateJobObjectW
)(
LPSECURITY_ATTRIBUTES
sa
,
LPCWSTR
name
);
static
HANDLE
(
WINAPI
*
pOpenJobObjectA
)(
DWORD
access
,
BOOL
inherit
,
LPCSTR
name
);
static
BOOL
(
WINAPI
*
pAssignProcessToJobObject
)(
HANDLE
job
,
HANDLE
process
);
static
BOOL
(
WINAPI
*
pAssignProcessToJobObject
)(
HANDLE
job
,
HANDLE
process
);
static
BOOL
(
WINAPI
*
pIsProcessInJob
)(
HANDLE
process
,
HANDLE
job
,
PBOOL
result
);
static
BOOL
(
WINAPI
*
pIsProcessInJob
)(
HANDLE
process
,
HANDLE
job
,
PBOOL
result
);
static
BOOL
(
WINAPI
*
pTerminateJobObject
)(
HANDLE
job
,
UINT
exit_code
);
static
BOOL
(
WINAPI
*
pTerminateJobObject
)(
HANDLE
job
,
UINT
exit_code
);
...
@@ -257,6 +258,7 @@ static BOOL init(void)
...
@@ -257,6 +258,7 @@ static BOOL init(void)
pQueryFullProcessImageNameW
=
(
void
*
)
GetProcAddress
(
hkernel32
,
"QueryFullProcessImageNameW"
);
pQueryFullProcessImageNameW
=
(
void
*
)
GetProcAddress
(
hkernel32
,
"QueryFullProcessImageNameW"
);
pK32GetProcessImageFileNameA
=
(
void
*
)
GetProcAddress
(
hkernel32
,
"K32GetProcessImageFileNameA"
);
pK32GetProcessImageFileNameA
=
(
void
*
)
GetProcAddress
(
hkernel32
,
"K32GetProcessImageFileNameA"
);
pCreateJobObjectW
=
(
void
*
)
GetProcAddress
(
hkernel32
,
"CreateJobObjectW"
);
pCreateJobObjectW
=
(
void
*
)
GetProcAddress
(
hkernel32
,
"CreateJobObjectW"
);
pOpenJobObjectA
=
(
void
*
)
GetProcAddress
(
hkernel32
,
"OpenJobObjectA"
);
pAssignProcessToJobObject
=
(
void
*
)
GetProcAddress
(
hkernel32
,
"AssignProcessToJobObject"
);
pAssignProcessToJobObject
=
(
void
*
)
GetProcAddress
(
hkernel32
,
"AssignProcessToJobObject"
);
pIsProcessInJob
=
(
void
*
)
GetProcAddress
(
hkernel32
,
"IsProcessInJob"
);
pIsProcessInJob
=
(
void
*
)
GetProcAddress
(
hkernel32
,
"IsProcessInJob"
);
pTerminateJobObject
=
(
void
*
)
GetProcAddress
(
hkernel32
,
"TerminateJobObject"
);
pTerminateJobObject
=
(
void
*
)
GetProcAddress
(
hkernel32
,
"TerminateJobObject"
);
...
@@ -2976,13 +2978,14 @@ static void test_jobInheritance(HANDLE job)
...
@@ -2976,13 +2978,14 @@ static void test_jobInheritance(HANDLE job)
wait_and_close_child_process
(
&
pi
);
wait_and_close_child_process
(
&
pi
);
}
}
static
void
test_BreakawayOk
(
HANDLE
job
)
static
void
test_BreakawayOk
(
HANDLE
parent_
job
)
{
{
JOBOBJECT_EXTENDED_LIMIT_INFORMATION
limit_info
;
JOBOBJECT_EXTENDED_LIMIT_INFORMATION
limit_info
;
PROCESS_INFORMATION
pi
;
PROCESS_INFORMATION
pi
;
STARTUPINFOA
si
=
{
0
};
STARTUPINFOA
si
=
{
0
};
char
buffer
[
MAX_PATH
+
23
];
char
buffer
[
MAX_PATH
+
23
];
BOOL
ret
,
out
;
BOOL
ret
,
out
,
nested_jobs
;
HANDLE
job
;
if
(
!
pIsProcessInJob
)
if
(
!
pIsProcessInJob
)
{
{
...
@@ -2990,6 +2993,16 @@ static void test_BreakawayOk(HANDLE job)
...
@@ -2990,6 +2993,16 @@ static void test_BreakawayOk(HANDLE job)
return
;
return
;
}
}
job
=
pCreateJobObjectW
(
NULL
,
NULL
);
ok
(
!!
job
,
"CreateJobObjectW error %u
\n
"
,
GetLastError
());
ret
=
pAssignProcessToJobObject
(
job
,
GetCurrentProcess
());
ok
(
ret
||
broken
(
!
ret
&&
GetLastError
()
==
ERROR_ACCESS_DENIED
)
/* before Win 8. */
,
"AssignProcessToJobObject error %u
\n
"
,
GetLastError
());
nested_jobs
=
ret
;
if
(
!
ret
)
win_skip
(
"Nested jobs are not supported.
\n
"
);
sprintf
(
buffer
,
"
\"
%s
\"
process exit"
,
selfname
);
sprintf
(
buffer
,
"
\"
%s
\"
process exit"
,
selfname
);
ret
=
CreateProcessA
(
NULL
,
buffer
,
NULL
,
NULL
,
FALSE
,
CREATE_BREAKAWAY_FROM_JOB
,
NULL
,
NULL
,
&
si
,
&
pi
);
ret
=
CreateProcessA
(
NULL
,
buffer
,
NULL
,
NULL
,
FALSE
,
CREATE_BREAKAWAY_FROM_JOB
,
NULL
,
NULL
,
&
si
,
&
pi
);
ok
(
!
ret
,
"CreateProcessA expected failure
\n
"
);
ok
(
!
ret
,
"CreateProcessA expected failure
\n
"
);
...
@@ -3001,10 +3014,32 @@ static void test_BreakawayOk(HANDLE job)
...
@@ -3001,10 +3014,32 @@ static void test_BreakawayOk(HANDLE job)
wait_and_close_child_process
(
&
pi
);
wait_and_close_child_process
(
&
pi
);
}
}
if
(
nested_jobs
)
{
limit_info
.
BasicLimitInformation
.
LimitFlags
=
JOB_OBJECT_LIMIT_BREAKAWAY_OK
;
limit_info
.
BasicLimitInformation
.
LimitFlags
=
JOB_OBJECT_LIMIT_BREAKAWAY_OK
;
ret
=
pSetInformationJobObject
(
job
,
JobObjectExtendedLimitInformation
,
&
limit_info
,
sizeof
(
limit_info
));
ret
=
pSetInformationJobObject
(
job
,
JobObjectExtendedLimitInformation
,
&
limit_info
,
sizeof
(
limit_info
));
ok
(
ret
,
"SetInformationJobObject error %u
\n
"
,
GetLastError
());
ok
(
ret
,
"SetInformationJobObject error %u
\n
"
,
GetLastError
());
sprintf
(
buffer
,
"
\"
%s
\"
process exit"
,
selfname
);
ret
=
CreateProcessA
(
NULL
,
buffer
,
NULL
,
NULL
,
FALSE
,
CREATE_BREAKAWAY_FROM_JOB
,
NULL
,
NULL
,
&
si
,
&
pi
);
ok
(
ret
,
"CreateProcessA error %u
\n
"
,
GetLastError
());
ret
=
pIsProcessInJob
(
pi
.
hProcess
,
job
,
&
out
);
ok
(
ret
,
"IsProcessInJob error %u
\n
"
,
GetLastError
());
ok
(
!
out
,
"IsProcessInJob returned out=%u
\n
"
,
out
);
ret
=
pIsProcessInJob
(
pi
.
hProcess
,
parent_job
,
&
out
);
ok
(
ret
,
"IsProcessInJob error %u
\n
"
,
GetLastError
());
ok
(
out
,
"IsProcessInJob returned out=%u
\n
"
,
out
);
TerminateProcess
(
pi
.
hProcess
,
0
);
wait_and_close_child_process
(
&
pi
);
}
limit_info
.
BasicLimitInformation
.
LimitFlags
=
JOB_OBJECT_LIMIT_BREAKAWAY_OK
;
ret
=
pSetInformationJobObject
(
parent_job
,
JobObjectExtendedLimitInformation
,
&
limit_info
,
sizeof
(
limit_info
));
ok
(
ret
,
"SetInformationJobObject error %u
\n
"
,
GetLastError
());
ret
=
CreateProcessA
(
NULL
,
buffer
,
NULL
,
NULL
,
FALSE
,
CREATE_BREAKAWAY_FROM_JOB
,
NULL
,
NULL
,
&
si
,
&
pi
);
ret
=
CreateProcessA
(
NULL
,
buffer
,
NULL
,
NULL
,
FALSE
,
CREATE_BREAKAWAY_FROM_JOB
,
NULL
,
NULL
,
&
si
,
&
pi
);
ok
(
ret
,
"CreateProcessA error %u
\n
"
,
GetLastError
());
ok
(
ret
,
"CreateProcessA error %u
\n
"
,
GetLastError
());
...
@@ -3012,6 +3047,10 @@ static void test_BreakawayOk(HANDLE job)
...
@@ -3012,6 +3047,10 @@ static void test_BreakawayOk(HANDLE job)
ok
(
ret
,
"IsProcessInJob error %u
\n
"
,
GetLastError
());
ok
(
ret
,
"IsProcessInJob error %u
\n
"
,
GetLastError
());
ok
(
!
out
,
"IsProcessInJob returned out=%u
\n
"
,
out
);
ok
(
!
out
,
"IsProcessInJob returned out=%u
\n
"
,
out
);
ret
=
pIsProcessInJob
(
pi
.
hProcess
,
parent_job
,
&
out
);
ok
(
ret
,
"IsProcessInJob error %u
\n
"
,
GetLastError
());
ok
(
!
out
,
"IsProcessInJob returned out=%u
\n
"
,
out
);
wait_and_close_child_process
(
&
pi
);
wait_and_close_child_process
(
&
pi
);
limit_info
.
BasicLimitInformation
.
LimitFlags
=
JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
;
limit_info
.
BasicLimitInformation
.
LimitFlags
=
JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
;
...
@@ -4309,6 +4348,135 @@ static void test_dead_process(void)
...
@@ -4309,6 +4348,135 @@ static void test_dead_process(void)
CloseHandle
(
pi
.
hThread
);
CloseHandle
(
pi
.
hThread
);
}
}
static
void
test_nested_jobs_child
(
unsigned
int
index
)
{
HANDLE
job
,
job_parent
,
job_other
;
PROCESS_INFORMATION
pi
;
char
job_name
[
32
];
BOOL
ret
,
out
;
sprintf
(
job_name
,
"test_nested_jobs_%u"
,
index
);
job
=
pOpenJobObjectA
(
JOB_OBJECT_ASSIGN_PROCESS
|
JOB_OBJECT_SET_ATTRIBUTES
|
JOB_OBJECT_QUERY
|
JOB_OBJECT_TERMINATE
,
FALSE
,
job_name
);
ok
(
!!
job
,
"OpenJobObjectA error %u
\n
"
,
GetLastError
());
sprintf
(
job_name
,
"test_nested_jobs_%u"
,
!
index
);
job_other
=
pOpenJobObjectA
(
JOB_OBJECT_ASSIGN_PROCESS
|
JOB_OBJECT_SET_ATTRIBUTES
|
JOB_OBJECT_QUERY
|
JOB_OBJECT_TERMINATE
,
FALSE
,
job_name
);
ok
(
!!
job_other
,
"OpenJobObjectA error %u
\n
"
,
GetLastError
());
job_parent
=
pCreateJobObjectW
(
NULL
,
NULL
);
ok
(
!!
job_parent
,
"CreateJobObjectA error %u
\n
"
,
GetLastError
());
ret
=
pAssignProcessToJobObject
(
job_parent
,
GetCurrentProcess
());
ok
(
ret
,
"AssignProcessToJobObject error %u
\n
"
,
GetLastError
());
create_process
(
"wait"
,
&
pi
);
ret
=
pAssignProcessToJobObject
(
job_parent
,
pi
.
hProcess
);
ok
(
ret
||
broken
(
!
ret
&&
GetLastError
()
==
ERROR_ACCESS_DENIED
)
/* Supported since Windows 8. */
,
"AssignProcessToJobObject error %u
\n
"
,
GetLastError
());
if
(
!
ret
)
{
win_skip
(
"Nested jobs are not supported.
\n
"
);
goto
done
;
}
ret
=
pAssignProcessToJobObject
(
job
,
pi
.
hProcess
);
ok
(
ret
,
"AssignProcessToJobObject error %u
\n
"
,
GetLastError
());
out
=
FALSE
;
ret
=
pIsProcessInJob
(
pi
.
hProcess
,
NULL
,
&
out
);
ok
(
ret
,
"IsProcessInJob error %u
\n
"
,
GetLastError
());
ok
(
out
,
"IsProcessInJob returned out=%u
\n
"
,
out
);
out
=
FALSE
;
ret
=
pIsProcessInJob
(
pi
.
hProcess
,
job
,
&
out
);
ok
(
ret
,
"IsProcessInJob error %u
\n
"
,
GetLastError
());
ok
(
out
,
"IsProcessInJob returned out=%u
\n
"
,
out
);
out
=
TRUE
;
ret
=
pIsProcessInJob
(
GetCurrentProcess
(),
job
,
&
out
);
ok
(
ret
,
"IsProcessInJob error %u
\n
"
,
GetLastError
());
ok
(
!
out
,
"IsProcessInJob returned out=%u
\n
"
,
out
);
out
=
FALSE
;
ret
=
pIsProcessInJob
(
pi
.
hProcess
,
job
,
&
out
);
ok
(
ret
,
"IsProcessInJob error %u
\n
"
,
GetLastError
());
ok
(
out
,
"IsProcessInJob returned out=%u
\n
"
,
out
);
ret
=
pAssignProcessToJobObject
(
job
,
GetCurrentProcess
());
ok
(
ret
,
"AssignProcessToJobObject error %u
\n
"
,
GetLastError
());
TerminateProcess
(
pi
.
hProcess
,
0
);
wait_child_process
(
pi
.
hProcess
);
CloseHandle
(
pi
.
hProcess
);
CloseHandle
(
pi
.
hThread
);
create_process
(
"wait"
,
&
pi
);
out
=
FALSE
;
ret
=
pIsProcessInJob
(
pi
.
hProcess
,
job
,
&
out
);
ok
(
ret
,
"IsProcessInJob error %u
\n
"
,
GetLastError
());
ok
(
out
,
"IsProcessInJob returned out=%u
\n
"
,
out
);
out
=
FALSE
;
ret
=
pIsProcessInJob
(
pi
.
hProcess
,
job_parent
,
&
out
);
ok
(
ret
,
"IsProcessInJob error %u
\n
"
,
GetLastError
());
ok
(
out
,
"IsProcessInJob returned out=%u
\n
"
,
out
);
if
(
index
)
{
ret
=
pAssignProcessToJobObject
(
job_other
,
GetCurrentProcess
());
ok
(
!
ret
,
"AssignProcessToJobObject succeded
\n
"
);
ok
(
GetLastError
()
==
ERROR_ACCESS_DENIED
,
"Got unexpected error %u.
\n
"
,
GetLastError
());
}
done:
TerminateProcess
(
pi
.
hProcess
,
0
);
wait_child_process
(
pi
.
hProcess
);
CloseHandle
(
pi
.
hProcess
);
CloseHandle
(
pi
.
hThread
);
CloseHandle
(
job_parent
);
CloseHandle
(
job
);
CloseHandle
(
job_other
);
}
static
void
test_nested_jobs
(
void
)
{
PROCESS_INFORMATION
info
[
2
];
char
buffer
[
MAX_PATH
+
26
];
STARTUPINFOA
si
=
{
0
};
HANDLE
job1
,
job2
;
unsigned
int
i
;
if
(
!
pIsProcessInJob
)
{
win_skip
(
"IsProcessInJob not available.
\n
"
);
return
;
}
job1
=
pCreateJobObjectW
(
NULL
,
L"test_nested_jobs_0"
);
ok
(
!!
job1
,
"CreateJobObjectW failed, error %u.
\n
"
,
GetLastError
());
job2
=
pCreateJobObjectW
(
NULL
,
L"test_nested_jobs_1"
);
ok
(
!!
job2
,
"CreateJobObjectW failed, error %u.
\n
"
,
GetLastError
());
sprintf
(
buffer
,
"
\"
%s
\"
process nested_jobs 0"
,
selfname
);
ok
(
CreateProcessA
(
NULL
,
buffer
,
NULL
,
NULL
,
FALSE
,
0
,
NULL
,
NULL
,
&
si
,
&
info
[
0
]),
"CreateProcess failed
\n
"
);
wait_child_process
(
info
[
0
].
hProcess
);
sprintf
(
buffer
,
"
\"
%s
\"
process nested_jobs 1"
,
selfname
);
ok
(
CreateProcessA
(
NULL
,
buffer
,
NULL
,
NULL
,
FALSE
,
0
,
NULL
,
NULL
,
&
si
,
&
info
[
1
]),
"CreateProcess failed
\n
"
);
wait_child_process
(
info
[
1
].
hProcess
);
for
(
i
=
0
;
i
<
2
;
++
i
)
{
CloseHandle
(
info
[
i
].
hProcess
);
CloseHandle
(
info
[
i
].
hThread
);
}
CloseHandle
(
job1
);
CloseHandle
(
job2
);
}
START_TEST
(
process
)
START_TEST
(
process
)
{
{
HANDLE
job
,
hproc
,
h
,
h2
;
HANDLE
job
,
hproc
,
h
,
h2
;
...
@@ -4384,6 +4552,11 @@ START_TEST(process)
...
@@ -4384,6 +4552,11 @@ START_TEST(process)
test_handle_list_attribute
(
TRUE
,
h
,
h2
);
test_handle_list_attribute
(
TRUE
,
h
,
h2
);
return
;
return
;
}
}
else
if
(
!
strcmp
(
myARGV
[
2
],
"nested_jobs"
)
&&
myARGC
>=
4
)
{
test_nested_jobs_child
(
atoi
(
myARGV
[
3
]));
return
;
}
ok
(
0
,
"Unexpected command %s
\n
"
,
myARGV
[
2
]);
ok
(
0
,
"Unexpected command %s
\n
"
,
myARGV
[
2
]);
return
;
return
;
...
@@ -4452,6 +4625,7 @@ START_TEST(process)
...
@@ -4452,6 +4625,7 @@ START_TEST(process)
test_CompletionPort
();
test_CompletionPort
();
test_KillOnJobClose
();
test_KillOnJobClose
();
test_WaitForJobObject
();
test_WaitForJobObject
();
test_nested_jobs
();
job
=
test_AddSelfToJob
();
job
=
test_AddSelfToJob
();
test_jobInheritance
(
job
);
test_jobInheritance
(
job
);
test_BreakawayOk
(
job
);
test_BreakawayOk
(
job
);
...
...
server/process.c
View file @
21f5597d
...
@@ -182,7 +182,7 @@ static void job_destroy( struct object *obj );
...
@@ -182,7 +182,7 @@ static void job_destroy( struct object *obj );
struct
job
struct
job
{
{
struct
object
obj
;
/* object header */
struct
object
obj
;
/* object header */
struct
list
process_list
;
/* list of
all
processes */
struct
list
process_list
;
/* list of processes */
int
num_processes
;
/* count of running processes */
int
num_processes
;
/* count of running processes */
int
total_processes
;
/* count of processes which have been assigned */
int
total_processes
;
/* count of processes which have been assigned */
unsigned
int
limit_flags
;
/* limit flags */
unsigned
int
limit_flags
;
/* limit flags */
...
@@ -190,6 +190,9 @@ struct job
...
@@ -190,6 +190,9 @@ struct job
int
signaled
;
/* job is signaled */
int
signaled
;
/* job is signaled */
struct
completion
*
completion_port
;
/* associated completion port */
struct
completion
*
completion_port
;
/* associated completion port */
apc_param_t
completion_key
;
/* key to send with completion messages */
apc_param_t
completion_key
;
/* key to send with completion messages */
struct
job
*
parent
;
struct
list
parent_job_entry
;
/* list entry for parent job */
struct
list
child_job_list
;
/* list of child jobs */
};
};
static
const
struct
object_ops
job_ops
=
static
const
struct
object_ops
job_ops
=
...
@@ -227,6 +230,7 @@ static struct job *create_job_object( struct object *root, const struct unicode_
...
@@ -227,6 +230,7 @@ static struct job *create_job_object( struct object *root, const struct unicode_
{
{
/* initialize it if it didn't already exist */
/* initialize it if it didn't already exist */
list_init
(
&
job
->
process_list
);
list_init
(
&
job
->
process_list
);
list_init
(
&
job
->
child_job_list
);
job
->
num_processes
=
0
;
job
->
num_processes
=
0
;
job
->
total_processes
=
0
;
job
->
total_processes
=
0
;
job
->
limit_flags
=
0
;
job
->
limit_flags
=
0
;
...
@@ -234,6 +238,7 @@ static struct job *create_job_object( struct object *root, const struct unicode_
...
@@ -234,6 +238,7 @@ static struct job *create_job_object( struct object *root, const struct unicode_
job
->
signaled
=
0
;
job
->
signaled
=
0
;
job
->
completion_port
=
NULL
;
job
->
completion_port
=
NULL
;
job
->
completion_key
=
0
;
job
->
completion_key
=
0
;
job
->
parent
=
NULL
;
}
}
}
}
return
job
;
return
job
;
...
@@ -250,14 +255,59 @@ static void add_job_completion( struct job *job, apc_param_t msg, apc_param_t pi
...
@@ -250,14 +255,59 @@ static void add_job_completion( struct job *job, apc_param_t msg, apc_param_t pi
add_completion
(
job
->
completion_port
,
job
->
completion_key
,
pid
,
STATUS_SUCCESS
,
msg
);
add_completion
(
job
->
completion_port
,
job
->
completion_key
,
pid
,
STATUS_SUCCESS
,
msg
);
}
}
static
int
process_in_job
(
struct
job
*
job
,
struct
process
*
process
)
{
struct
job
*
j
;
LIST_FOR_EACH_ENTRY
(
j
,
&
job
->
child_job_list
,
struct
job
,
parent_job_entry
)
{
assert
(
j
->
parent
==
job
);
if
(
process_in_job
(
j
,
process
))
return
1
;
}
return
process
->
job
==
job
;
}
static
void
add_job_process
(
struct
job
*
job
,
struct
process
*
process
)
static
void
add_job_process
(
struct
job
*
job
,
struct
process
*
process
)
{
{
struct
job
*
j
,
*
common_parent
;
process_id_t
pid
;
if
(
job
==
process
->
job
)
return
;
if
((
common_parent
=
process
->
job
))
{
if
(
job
->
parent
)
{
for
(
j
=
job
->
parent
;
j
;
j
=
j
->
parent
)
if
(
j
==
common_parent
)
break
;
if
(
j
!=
common_parent
)
{
/* Job already has parent and the process is not in the job's chain. */
set_error
(
STATUS_ACCESS_DENIED
);
return
;
}
/* process->job is referenced in the job->parent chain. */
release_object
(
process
->
job
);
}
else
{
/* transfer reference. */
job
->
parent
=
process
->
job
;
list_add_tail
(
&
job
->
parent
->
child_job_list
,
&
job
->
parent_job_entry
);
}
list_remove
(
&
process
->
job_entry
);
}
process
->
job
=
(
struct
job
*
)
grab_object
(
job
);
process
->
job
=
(
struct
job
*
)
grab_object
(
job
);
list_add_tail
(
&
job
->
process_list
,
&
process
->
job_entry
);
list_add_tail
(
&
job
->
process_list
,
&
process
->
job_entry
);
job
->
num_processes
++
;
job
->
total_processes
++
;
add_job_completion
(
job
,
JOB_OBJECT_MSG_NEW_PROCESS
,
get_process_id
(
process
)
);
pid
=
get_process_id
(
process
);
for
(
j
=
job
;
j
!=
common_parent
;
j
=
j
->
parent
)
{
j
->
num_processes
++
;
j
->
total_processes
++
;
add_job_completion
(
j
,
JOB_OBJECT_MSG_NEW_PROCESS
,
pid
);
}
}
}
/* called when a process has terminated, allow one additional process */
/* called when a process has terminated, allow one additional process */
...
@@ -265,8 +315,8 @@ static void release_job_process( struct process *process )
...
@@ -265,8 +315,8 @@ static void release_job_process( struct process *process )
{
{
struct
job
*
job
=
process
->
job
;
struct
job
*
job
=
process
->
job
;
if
(
!
job
)
return
;
while
(
job
)
{
assert
(
job
->
num_processes
);
assert
(
job
->
num_processes
);
job
->
num_processes
--
;
job
->
num_processes
--
;
...
@@ -275,27 +325,31 @@ static void release_job_process( struct process *process )
...
@@ -275,27 +325,31 @@ static void release_job_process( struct process *process )
if
(
!
job
->
num_processes
)
if
(
!
job
->
num_processes
)
add_job_completion
(
job
,
JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO
,
0
);
add_job_completion
(
job
,
JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO
,
0
);
job
=
job
->
parent
;
}
}
}
static
void
terminate_job
(
struct
job
*
job
,
int
exit_code
)
static
void
terminate_job
(
struct
job
*
job
,
int
exit_code
)
{
{
/* don't report completion events for terminated processes */
struct
process
*
process
,
*
next_process
;
job
->
terminating
=
1
;
struct
job
*
j
,
*
next_job
;
for
(;;)
/* restart from the beginning of the list every time */
LIST_FOR_EACH_ENTRY_SAFE
(
j
,
next_job
,
&
job
->
child_job_list
,
struct
job
,
parent_job_entry
)
{
{
struct
process
*
process
;
assert
(
j
->
parent
==
job
)
;
/* find the first process associated with this job and still running */
grab_object
(
j
);
LIST_FOR_EACH_ENTRY
(
process
,
&
job
->
process_list
,
struct
process
,
job_entry
)
terminate_job
(
j
,
exit_code
);
{
release_object
(
j
);
if
(
process
->
running_threads
)
break
;
}
}
if
(
&
process
->
job_entry
==
&
job
->
process_list
)
break
;
/* no process found */
job
->
terminating
=
1
;
LIST_FOR_EACH_ENTRY_SAFE
(
process
,
next_process
,
&
job
->
process_list
,
struct
process
,
job_entry
)
{
assert
(
process
->
job
==
job
);
assert
(
process
->
job
==
job
);
terminate_process
(
process
,
NULL
,
exit_code
);
if
(
process
->
running_threads
)
terminate_process
(
process
,
NULL
,
exit_code
);
}
}
job
->
terminating
=
0
;
job
->
terminating
=
0
;
job
->
signaled
=
1
;
job
->
signaled
=
1
;
wake_up
(
&
job
->
obj
,
0
);
wake_up
(
&
job
->
obj
,
0
);
...
@@ -320,16 +374,23 @@ static void job_destroy( struct object *obj )
...
@@ -320,16 +374,23 @@ static void job_destroy( struct object *obj )
assert
(
obj
->
ops
==
&
job_ops
);
assert
(
obj
->
ops
==
&
job_ops
);
assert
(
!
job
->
num_processes
);
assert
(
!
job
->
num_processes
);
assert
(
list_empty
(
&
job
->
process_list
)
);
assert
(
list_empty
(
&
job
->
process_list
));
assert
(
list_empty
(
&
job
->
child_job_list
));
if
(
job
->
completion_port
)
release_object
(
job
->
completion_port
);
if
(
job
->
completion_port
)
release_object
(
job
->
completion_port
);
if
(
job
->
parent
)
{
list_remove
(
&
job
->
parent_job_entry
);
release_object
(
job
->
parent
);
}
}
}
static
void
job_dump
(
struct
object
*
obj
,
int
verbose
)
static
void
job_dump
(
struct
object
*
obj
,
int
verbose
)
{
{
struct
job
*
job
=
(
struct
job
*
)
obj
;
struct
job
*
job
=
(
struct
job
*
)
obj
;
assert
(
obj
->
ops
==
&
job_ops
);
assert
(
obj
->
ops
==
&
job_ops
);
fprintf
(
stderr
,
"Job processes=%d
\n
"
,
list_count
(
&
job
->
process_list
)
);
fprintf
(
stderr
,
"Job processes=%d child_jobs=%d parent=%p
\n
"
,
list_count
(
&
job
->
process_list
),
list_count
(
&
job
->
child_job_list
),
job
->
parent
);
}
}
static
int
job_signaled
(
struct
object
*
obj
,
struct
wait_queue_entry
*
entry
)
static
int
job_signaled
(
struct
object
*
obj
,
struct
wait_queue_entry
*
entry
)
...
@@ -1026,6 +1087,7 @@ DECL_HANDLER(new_process)
...
@@ -1026,6 +1087,7 @@ DECL_HANDLER(new_process)
struct
thread
*
parent_thread
=
current
;
struct
thread
*
parent_thread
=
current
;
int
socket_fd
=
thread_get_inflight_fd
(
current
,
req
->
socket_fd
);
int
socket_fd
=
thread_get_inflight_fd
(
current
,
req
->
socket_fd
);
const
obj_handle_t
*
handles
=
NULL
;
const
obj_handle_t
*
handles
=
NULL
;
struct
job
*
job
;
if
(
socket_fd
==
-
1
)
if
(
socket_fd
==
-
1
)
{
{
...
@@ -1062,6 +1124,8 @@ DECL_HANDLER(new_process)
...
@@ -1062,6 +1124,8 @@ DECL_HANDLER(new_process)
}
}
else
parent
=
(
struct
process
*
)
grab_object
(
current
->
process
);
else
parent
=
(
struct
process
*
)
grab_object
(
current
->
process
);
/* If a job further in the job chain does not permit breakaway process creation
* succeeds and the process which is trying to breakaway is assigned to that job. */
if
(
parent
->
job
&&
(
req
->
flags
&
PROCESS_CREATE_FLAGS_BREAKAWAY
)
&&
if
(
parent
->
job
&&
(
req
->
flags
&
PROCESS_CREATE_FLAGS_BREAKAWAY
)
&&
!
(
parent
->
job
->
limit_flags
&
(
JOB_OBJECT_LIMIT_BREAKAWAY_OK
|
JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
)))
!
(
parent
->
job
->
limit_flags
&
(
JOB_OBJECT_LIMIT_BREAKAWAY_OK
|
JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
)))
{
{
...
@@ -1152,11 +1216,18 @@ DECL_HANDLER(new_process)
...
@@ -1152,11 +1216,18 @@ DECL_HANDLER(new_process)
process
->
startup_info
=
(
struct
startup_info
*
)
grab_object
(
info
);
process
->
startup_info
=
(
struct
startup_info
*
)
grab_object
(
info
);
if
(
parent
->
job
job
=
parent
->
job
;
&&
!
(
req
->
flags
&
PROCESS_CREATE_FLAGS_BREAKAWAY
)
while
(
job
)
&&
!
(
parent
->
job
->
limit_flags
&
JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
))
{
{
add_job_process
(
parent
->
job
,
process
);
if
(
!
(
job
->
limit_flags
&
JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
)
&&
!
(
req
->
flags
&
PROCESS_CREATE_FLAGS_BREAKAWAY
&&
job
->
limit_flags
&
JOB_OBJECT_LIMIT_BREAKAWAY_OK
))
{
add_job_process
(
job
,
process
);
assert
(
!
get_error
()
);
break
;
}
job
=
job
->
parent
;
}
}
/* connect to the window station */
/* connect to the window station */
...
@@ -1570,12 +1641,8 @@ DECL_HANDLER(assign_job)
...
@@ -1570,12 +1641,8 @@ DECL_HANDLER(assign_job)
if
((
process
=
get_process_from_handle
(
req
->
process
,
PROCESS_SET_QUOTA
|
PROCESS_TERMINATE
)))
if
((
process
=
get_process_from_handle
(
req
->
process
,
PROCESS_SET_QUOTA
|
PROCESS_TERMINATE
)))
{
{
if
(
!
process
->
running_threads
)
if
(
!
process
->
running_threads
)
set_error
(
STATUS_PROCESS_IS_TERMINATING
);
set_error
(
STATUS_PROCESS_IS_TERMINATING
);
else
add_job_process
(
job
,
process
);
else
if
(
process
->
job
)
set_error
(
STATUS_ACCESS_DENIED
);
else
add_job_process
(
job
,
process
);
release_object
(
process
);
release_object
(
process
);
}
}
release_object
(
job
);
release_object
(
job
);
...
@@ -1597,7 +1664,7 @@ DECL_HANDLER(process_in_job)
...
@@ -1597,7 +1664,7 @@ DECL_HANDLER(process_in_job)
}
}
else
if
((
job
=
get_job_obj
(
current
->
process
,
req
->
job
,
JOB_OBJECT_QUERY
)))
else
if
((
job
=
get_job_obj
(
current
->
process
,
req
->
job
,
JOB_OBJECT_QUERY
)))
{
{
set_error
(
process
->
job
==
job
?
STATUS_PROCESS_IN_JOB
:
STATUS_PROCESS_NOT_IN_JOB
);
set_error
(
process
_in_job
(
job
,
process
)
?
STATUS_PROCESS_IN_JOB
:
STATUS_PROCESS_NOT_IN_JOB
);
release_object
(
job
);
release_object
(
job
);
}
}
release_object
(
process
);
release_object
(
process
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment