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
6ca1d1b0
Commit
6ca1d1b0
authored
Jan 15, 2007
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
server: Support queuing some APCs to a process instead of a thread.
parent
fb40dc40
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
160 additions
and
29 deletions
+160
-29
ntdll_misc.h
dlls/ntdll/ntdll_misc.h
+1
-0
sync.c
dlls/ntdll/sync.c
+36
-0
thread.c
dlls/ntdll/thread.c
+1
-1
server_protocol.h
include/wine/server_protocol.h
+4
-2
protocol.def
server/protocol.def
+5
-2
thread.c
server/thread.c
+103
-22
trace.c
server/trace.c
+10
-2
No files found.
dlls/ntdll/ntdll_misc.h
View file @
6ca1d1b0
...
...
@@ -42,6 +42,7 @@ extern void dump_ObjectAttributes (const OBJECT_ATTRIBUTES *ObjectAttributes);
extern
void
NTDLL_get_server_abstime
(
abs_time_t
*
when
,
const
LARGE_INTEGER
*
timeout
);
extern
void
NTDLL_from_server_abstime
(
LARGE_INTEGER
*
time
,
const
abs_time_t
*
when
);
extern
NTSTATUS
NTDLL_queue_process_apc
(
HANDLE
process
,
const
apc_call_t
*
call
,
apc_result_t
*
result
);
extern
NTSTATUS
NTDLL_wait_for_multiple_objects
(
UINT
count
,
const
HANDLE
*
handles
,
UINT
flags
,
const
LARGE_INTEGER
*
timeout
,
HANDLE
signal_object
);
...
...
dlls/ntdll/sync.c
View file @
6ca1d1b0
...
...
@@ -715,6 +715,42 @@ static BOOL call_apcs( BOOL alertable )
/***********************************************************************
* NTDLL_queue_process_apc
*/
NTSTATUS
NTDLL_queue_process_apc
(
HANDLE
process
,
const
apc_call_t
*
call
,
apc_result_t
*
result
)
{
for
(;;)
{
NTSTATUS
ret
;
HANDLE
handle
=
0
;
SERVER_START_REQ
(
queue_apc
)
{
req
->
process
=
process
;
req
->
call
=
*
call
;
if
(
!
(
ret
=
wine_server_call
(
req
)))
handle
=
reply
->
handle
;
}
SERVER_END_REQ
;
if
(
!
handle
)
return
ret
;
NtWaitForSingleObject
(
handle
,
FALSE
,
NULL
);
SERVER_START_REQ
(
get_apc_result
)
{
req
->
handle
=
handle
;
if
(
!
(
ret
=
wine_server_call
(
req
)))
*
result
=
reply
->
result
;
}
SERVER_END_REQ
;
if
(
!
ret
&&
result
->
type
==
APC_NONE
)
continue
;
/* APC didn't run, try again */
if
(
ret
)
NtClose
(
handle
);
return
ret
;
}
}
/***********************************************************************
* NTDLL_wait_for_multiple_objects
*
* Implementation of NtWaitForMultipleObjects
...
...
dlls/ntdll/thread.c
View file @
6ca1d1b0
...
...
@@ -622,7 +622,7 @@ NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1
NTSTATUS
ret
;
SERVER_START_REQ
(
queue_apc
)
{
req
->
handle
=
handle
;
req
->
thread
=
handle
;
if
(
func
)
{
req
->
call
.
type
=
APC_USER
;
...
...
include/wine/server_protocol.h
View file @
6ca1d1b0
...
...
@@ -582,12 +582,14 @@ struct unload_dll_reply
struct
queue_apc_request
{
struct
request_header
__header
;
obj_handle_t
handle
;
obj_handle_t
thread
;
obj_handle_t
process
;
apc_call_t
call
;
};
struct
queue_apc_reply
{
struct
reply_header
__header
;
obj_handle_t
handle
;
};
...
...
@@ -4497,6 +4499,6 @@ union generic_reply
struct
query_symlink_reply
query_symlink_reply
;
};
#define SERVER_PROTOCOL_VERSION 26
5
#define SERVER_PROTOCOL_VERSION 26
6
#endif
/* __WINE_WINE_SERVER_PROTOCOL_H */
server/protocol.def
View file @
6ca1d1b0
...
...
@@ -504,10 +504,13 @@ typedef union
@END
/* Queue an APC for a thread */
/* Queue an APC for a thread
or process
*/
@REQ(queue_apc)
obj_handle_t handle; /* thread handle */
obj_handle_t thread; /* thread handle */
obj_handle_t process; /* process handle */
apc_call_t call; /* call arguments */
@REPLY
obj_handle_t handle; /* APC handle */
@END
...
...
server/thread.c
View file @
6ca1d1b0
...
...
@@ -312,6 +312,21 @@ static int thread_apc_signaled( struct object *obj, struct thread *thread )
return
apc
->
executed
;
}
/* queue an async procedure call */
static
struct
thread_apc
*
create_apc
(
struct
object
*
owner
,
const
apc_call_t
*
call_data
)
{
struct
thread_apc
*
apc
;
if
((
apc
=
alloc_object
(
&
thread_apc_ops
)))
{
apc
->
call
=
*
call_data
;
apc
->
owner
=
owner
;
apc
->
executed
=
0
;
apc
->
result
.
type
=
APC_NONE
;
}
return
apc
;
}
/* get a thread pointer from a thread id (and increment the refcount) */
struct
thread
*
get_thread_from_id
(
thread_id_t
id
)
{
...
...
@@ -679,20 +694,49 @@ static inline struct list *get_apc_queue( struct thread *thread, enum apc_type t
}
}
/* queue an
async procedure call
*/
int
thread_queue_apc
(
struct
thread
*
thread
,
struct
object
*
owner
,
const
apc_call_t
*
call_data
)
/* queue an
existing APC to a given thread
*/
static
int
queue_apc
(
struct
process
*
process
,
struct
thread
*
thread
,
struct
thread_apc
*
apc
)
{
struct
thread_apc
*
apc
;
struct
list
*
queue
=
get_apc_queue
(
thread
,
call_data
->
type
);
struct
list
*
queue
;
/* cancel a possible previous APC with the same owner
*/
if
(
owner
)
thread_cancel_apc
(
thread
,
owner
,
call_data
->
type
);
if
(
thread
->
state
==
TERMINATED
)
return
0
;
if
(
!
thread
)
/* find a suitable thread inside the process
*/
{
struct
thread
*
candidate
;
if
(
!
(
apc
=
alloc_object
(
&
thread_apc_ops
)))
return
0
;
apc
->
call
=
*
call_data
;
apc
->
owner
=
owner
;
apc
->
executed
=
0
;
/* first try to find a waiting thread */
LIST_FOR_EACH_ENTRY
(
candidate
,
&
process
->
thread_list
,
struct
thread
,
proc_entry
)
{
if
(
candidate
->
state
==
TERMINATED
)
continue
;
if
(
process
->
suspend
||
candidate
->
suspend
||
(
candidate
->
wait
&&
(
candidate
->
wait
->
flags
&
SELECT_INTERRUPTIBLE
)))
{
thread
=
candidate
;
break
;
}
}
if
(
!
thread
)
{
/* then use the first one that accepts a signal */
LIST_FOR_EACH_ENTRY
(
candidate
,
&
process
->
thread_list
,
struct
thread
,
proc_entry
)
{
if
(
send_thread_signal
(
candidate
,
SIGUSR1
))
{
thread
=
candidate
;
break
;
}
}
}
if
(
!
thread
)
return
0
;
/* nothing found */
}
else
{
if
(
thread
->
state
==
TERMINATED
)
return
0
;
/* cancel a possible previous APC with the same owner */
if
(
apc
->
owner
)
thread_cancel_apc
(
thread
,
apc
->
owner
,
apc
->
call
.
type
);
}
queue
=
get_apc_queue
(
thread
,
apc
->
call
.
type
);
grab_object
(
apc
);
list_add_tail
(
queue
,
&
apc
->
entry
);
if
(
!
list_prev
(
queue
,
&
apc
->
entry
))
/* first one */
wake_thread
(
thread
);
...
...
@@ -700,6 +744,20 @@ int thread_queue_apc( struct thread *thread, struct object *owner, const apc_cal
return
1
;
}
/* queue an async procedure call */
int
thread_queue_apc
(
struct
thread
*
thread
,
struct
object
*
owner
,
const
apc_call_t
*
call_data
)
{
struct
thread_apc
*
apc
;
int
ret
=
0
;
if
((
apc
=
create_apc
(
owner
,
call_data
)))
{
ret
=
queue_apc
(
NULL
,
thread
,
apc
);
release_object
(
apc
);
}
return
ret
;
}
/* cancel the async procedure call owned by a specific object */
void
thread_cancel_apc
(
struct
thread
*
thread
,
struct
object
*
owner
,
enum
apc_type
type
)
{
...
...
@@ -1076,24 +1134,47 @@ DECL_HANDLER(select)
select_on
(
count
,
req
->
cookie
,
get_req_data
(),
req
->
flags
,
&
req
->
timeout
,
req
->
signal
);
}
/* queue an APC for a thread */
/* queue an APC for a thread
or process
*/
DECL_HANDLER
(
queue_apc
)
{
struct
thread
*
thread
;
if
((
thread
=
get_thread_from_handle
(
req
->
handle
,
THREAD_SET_CONTEXT
)))
struct
process
*
process
;
struct
thread_apc
*
apc
;
if
(
!
(
apc
=
create_apc
(
NULL
,
&
req
->
call
)))
return
;
switch
(
apc
->
call
.
type
)
{
switch
(
req
->
call
.
type
)
case
APC_NONE
:
case
APC_USER
:
if
((
thread
=
get_thread_from_handle
(
req
->
thread
,
THREAD_SET_CONTEXT
)))
{
case
APC_NONE
:
case
APC_USER
:
thread_queue_apc
(
thread
,
NULL
,
&
req
->
call
);
break
;
default
:
set_error
(
STATUS_INVALID_PARAMETER
);
break
;
if
(
!
queue_apc
(
NULL
,
thread
,
apc
))
set_error
(
STATUS_THREAD_IS_TERMINATING
);
release_object
(
thread
);
}
release_object
(
thread
);
break
;
case
APC_VIRTUAL_ALLOC
:
case
APC_VIRTUAL_FREE
:
if
((
process
=
get_process_from_handle
(
req
->
process
,
PROCESS_VM_OPERATION
)))
{
obj_handle_t
handle
=
alloc_handle
(
current
->
process
,
apc
,
SYNCHRONIZE
,
0
);
if
(
handle
)
{
if
(
queue_apc
(
process
,
NULL
,
apc
))
reply
->
handle
=
handle
;
else
{
close_handle
(
current
->
process
,
handle
);
set_error
(
STATUS_PROCESS_IS_TERMINATING
);
}
}
release_object
(
process
);
}
break
;
default
:
set_error
(
STATUS_INVALID_PARAMETER
);
break
;
}
release_object
(
apc
);
}
/* get next APC to call */
...
...
server/trace.c
View file @
6ca1d1b0
...
...
@@ -909,11 +909,17 @@ static void dump_unload_dll_request( const struct unload_dll_request *req )
static
void
dump_queue_apc_request
(
const
struct
queue_apc_request
*
req
)
{
fprintf
(
stderr
,
" handle=%p,"
,
req
->
handle
);
fprintf
(
stderr
,
" thread=%p,"
,
req
->
thread
);
fprintf
(
stderr
,
" process=%p,"
,
req
->
process
);
fprintf
(
stderr
,
" call="
);
dump_apc_call
(
&
req
->
call
);
}
static
void
dump_queue_apc_reply
(
const
struct
queue_apc_reply
*
req
)
{
fprintf
(
stderr
,
" handle=%p"
,
req
->
handle
);
}
static
void
dump_get_apc_request
(
const
struct
get_apc_request
*
req
)
{
fprintf
(
stderr
,
" alertable=%d,"
,
req
->
alertable
);
...
...
@@ -3573,7 +3579,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(
dump_func
)
dump_resume_thread_reply
,
(
dump_func
)
0
,
(
dump_func
)
0
,
(
dump_func
)
0
,
(
dump_func
)
dump_queue_apc_reply
,
(
dump_func
)
dump_get_apc_reply
,
(
dump_func
)
dump_get_apc_result_reply
,
(
dump_func
)
0
,
...
...
@@ -4057,10 +4063,12 @@ static const struct
{
"PIPE_LISTENING"
,
STATUS_PIPE_LISTENING
},
{
"PIPE_NOT_AVAILABLE"
,
STATUS_PIPE_NOT_AVAILABLE
},
{
"PRIVILEGE_NOT_HELD"
,
STATUS_PRIVILEGE_NOT_HELD
},
{
"PROCESS_IS_TERMINATING"
,
STATUS_PROCESS_IS_TERMINATING
},
{
"SECTION_TOO_BIG"
,
STATUS_SECTION_TOO_BIG
},
{
"SEMAPHORE_LIMIT_EXCEEDED"
,
STATUS_SEMAPHORE_LIMIT_EXCEEDED
},
{
"SHARING_VIOLATION"
,
STATUS_SHARING_VIOLATION
},
{
"SUSPEND_COUNT_EXCEEDED"
,
STATUS_SUSPEND_COUNT_EXCEEDED
},
{
"THREAD_IS_TERMINATING"
,
STATUS_THREAD_IS_TERMINATING
},
{
"TIMEOUT"
,
STATUS_TIMEOUT
},
{
"TOO_MANY_OPENED_FILES"
,
STATUS_TOO_MANY_OPENED_FILES
},
{
"UNSUCCESSFUL"
,
STATUS_UNSUCCESSFUL
},
...
...
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