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
61e08b34
Commit
61e08b34
authored
May 08, 2007
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
server: Add support for queuing ioctl calls to a device.
parent
b43dc15c
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
191 additions
and
5 deletions
+191
-5
async.c
server/async.c
+1
-1
device.c
server/device.c
+189
-4
file.h
server/file.h
+1
-0
No files found.
server/async.c
View file @
61e08b34
...
...
@@ -127,7 +127,7 @@ static void async_queue_dump( struct object *obj, int verbose )
}
/* notifies client thread of new status of its async request */
static
void
async_terminate
(
struct
async
*
async
,
unsigned
int
status
)
void
async_terminate
(
struct
async
*
async
,
unsigned
int
status
)
{
apc_call_t
data
;
...
...
server/device.c
View file @
61e08b34
...
...
@@ -33,22 +33,63 @@
#include "handle.h"
#include "request.h"
struct
ioctl_call
{
struct
object
obj
;
/* object header */
struct
list
dev_entry
;
/* entry in device queue */
struct
list
mgr_entry
;
/* entry in manager queue */
struct
device
*
device
;
/* device containing this ioctl */
struct
thread
*
thread
;
/* thread that queued the ioctl */
void
*
user_arg
;
/* user arg used to identify the request */
struct
async
*
async
;
/* pending async op */
ioctl_code_t
code
;
/* ioctl code */
unsigned
int
status
;
/* resulting status (or STATUS_PENDING) */
data_size_t
in_size
;
/* size of input data */
void
*
in_data
;
/* input data */
data_size_t
out_size
;
/* size of output data */
void
*
out_data
;
/* output data */
};
static
void
ioctl_call_dump
(
struct
object
*
obj
,
int
verbose
);
static
int
ioctl_call_signaled
(
struct
object
*
obj
,
struct
thread
*
thread
);
static
void
ioctl_call_destroy
(
struct
object
*
obj
);
static
const
struct
object_ops
ioctl_call_ops
=
{
sizeof
(
struct
ioctl_call
),
/* size */
ioctl_call_dump
,
/* dump */
add_queue
,
/* add_queue */
remove_queue
,
/* remove_queue */
ioctl_call_signaled
,
/* signaled */
no_satisfied
,
/* satisfied */
no_signal
,
/* signal */
no_get_fd
,
/* get_fd */
no_map_access
,
/* map_access */
no_lookup_name
,
/* lookup_name */
no_open_file
,
/* open_file */
no_close_handle
,
/* close_handle */
ioctl_call_destroy
/* destroy */
};
struct
device_manager
{
struct
object
obj
;
/* object header */
struct
list
devices
;
/* list of devices */
struct
list
requests
;
/* list of pending ioctls across all devices */
};
static
void
device_manager_dump
(
struct
object
*
obj
,
int
verbose
);
static
int
device_manager_signaled
(
struct
object
*
obj
,
struct
thread
*
thread
);
static
void
device_manager_destroy
(
struct
object
*
obj
);
static
const
struct
object_ops
device_manager_ops
=
{
sizeof
(
struct
device_manager
),
/* size */
device_manager_dump
,
/* dump */
no_add_queue
,
/* add_queue */
NULL
,
/* remove_queue */
NULL
,
/* signaled */
add_queue
,
/* add_queue */
remove_queue
,
/* remove_queue */
device_manager_signaled
,
/* signaled */
no_satisfied
,
/* satisfied */
no_signal
,
/* signal */
no_get_fd
,
/* get_fd */
...
...
@@ -67,6 +108,7 @@ struct device
struct
fd
*
fd
;
/* file descriptor for ioctl */
void
*
user_ptr
;
/* opaque ptr for client side */
struct
list
entry
;
/* entry in device manager list */
struct
list
requests
;
/* list of pending ioctl requests */
};
static
void
device_dump
(
struct
object
*
obj
,
int
verbose
);
...
...
@@ -75,6 +117,8 @@ static void device_destroy( struct object *obj );
static
struct
object
*
device_open_file
(
struct
object
*
obj
,
unsigned
int
access
,
unsigned
int
sharing
,
unsigned
int
options
);
static
enum
server_fd_type
device_get_fd_type
(
struct
fd
*
fd
);
static
obj_handle_t
device_ioctl
(
struct
fd
*
fd
,
ioctl_code_t
code
,
const
async_data_t
*
async_data
,
const
void
*
data
,
data_size_t
size
);
static
const
struct
object_ops
device_ops
=
{
...
...
@@ -99,13 +143,91 @@ static const struct fd_ops device_fd_ops =
default_poll_event
,
/* poll_event */
no_flush
,
/* flush */
device_get_fd_type
,
/* get_fd_type */
de
fault_fd_ioctl
,
/* ioctl */
de
vice_ioctl
,
/* ioctl */
default_fd_queue_async
,
/* queue_async */
default_fd_reselect_async
,
/* reselect_async */
default_fd_cancel_async
/* cancel_async */
};
static
void
ioctl_call_dump
(
struct
object
*
obj
,
int
verbose
)
{
struct
ioctl_call
*
ioctl
=
(
struct
ioctl_call
*
)
obj
;
fprintf
(
stderr
,
"Ioctl call code=%08x device=%p
\n
"
,
ioctl
->
code
,
ioctl
->
device
);
}
static
int
ioctl_call_signaled
(
struct
object
*
obj
,
struct
thread
*
thread
)
{
struct
ioctl_call
*
ioctl
=
(
struct
ioctl_call
*
)
obj
;
return
!
ioctl
->
device
;
/* device is cleared once the ioctl has completed */
}
static
void
ioctl_call_destroy
(
struct
object
*
obj
)
{
struct
ioctl_call
*
ioctl
=
(
struct
ioctl_call
*
)
obj
;
free
(
ioctl
->
in_data
);
free
(
ioctl
->
out_data
);
if
(
ioctl
->
async
)
{
async_terminate
(
ioctl
->
async
,
STATUS_CANCELLED
);
release_object
(
ioctl
->
async
);
}
if
(
ioctl
->
device
)
release_object
(
ioctl
->
device
);
release_object
(
ioctl
->
thread
);
}
static
struct
ioctl_call
*
create_ioctl
(
struct
device
*
device
,
ioctl_code_t
code
,
const
void
*
in_data
,
data_size_t
in_size
,
data_size_t
out_size
)
{
struct
ioctl_call
*
ioctl
;
if
((
ioctl
=
alloc_object
(
&
ioctl_call_ops
)))
{
ioctl
->
device
=
(
struct
device
*
)
grab_object
(
device
);
ioctl
->
code
=
code
;
ioctl
->
async
=
NULL
;
ioctl
->
status
=
STATUS_PENDING
;
ioctl
->
in_size
=
in_size
;
ioctl
->
in_data
=
NULL
;
ioctl
->
out_size
=
out_size
;
ioctl
->
out_data
=
NULL
;
if
(
ioctl
->
in_size
&&
!
(
ioctl
->
in_data
=
memdup
(
in_data
,
in_size
)))
{
release_object
(
ioctl
);
ioctl
=
NULL
;
}
}
return
ioctl
;
}
static
void
set_ioctl_result
(
struct
ioctl_call
*
ioctl
,
unsigned
int
status
,
const
void
*
out_data
,
data_size_t
out_size
)
{
struct
device
*
device
=
ioctl
->
device
;
if
(
!
device
)
return
;
/* already finished */
/* FIXME: handle the STATUS_PENDING case */
ioctl
->
status
=
status
;
ioctl
->
out_size
=
min
(
ioctl
->
out_size
,
out_size
);
if
(
ioctl
->
out_size
&&
!
(
ioctl
->
out_data
=
memdup
(
out_data
,
ioctl
->
out_size
)))
ioctl
->
out_size
=
0
;
release_object
(
device
);
ioctl
->
device
=
NULL
;
if
(
ioctl
->
async
)
{
async_terminate
(
ioctl
->
async
,
ioctl
->
out_size
?
STATUS_ALERTED
:
status
);
release_object
(
ioctl
->
async
);
ioctl
->
async
=
NULL
;
}
wake_up
(
&
ioctl
->
obj
,
0
);
}
static
void
device_dump
(
struct
object
*
obj
,
int
verbose
)
{
struct
device
*
device
=
(
struct
device
*
)
obj
;
...
...
@@ -125,7 +247,13 @@ static struct fd *device_get_fd( struct object *obj )
static
void
device_destroy
(
struct
object
*
obj
)
{
struct
device
*
device
=
(
struct
device
*
)
obj
;
struct
ioctl_call
*
ioctl
,
*
next
;
LIST_FOR_EACH_ENTRY_SAFE
(
ioctl
,
next
,
&
device
->
requests
,
struct
ioctl_call
,
dev_entry
)
{
list_remove
(
&
ioctl
->
dev_entry
);
release_object
(
ioctl
);
/* no longer on the device queue */
}
if
(
device
->
fd
)
release_object
(
device
->
fd
);
if
(
device
->
manager
)
list_remove
(
&
device
->
entry
);
}
...
...
@@ -141,6 +269,46 @@ static enum server_fd_type device_get_fd_type( struct fd *fd )
return
FD_TYPE_DEVICE
;
}
static
obj_handle_t
device_ioctl
(
struct
fd
*
fd
,
ioctl_code_t
code
,
const
async_data_t
*
async_data
,
const
void
*
data
,
data_size_t
size
)
{
struct
device
*
device
=
get_fd_user
(
fd
);
struct
ioctl_call
*
ioctl
;
obj_handle_t
handle
;
if
(
!
device
->
manager
)
/* it has been deleted */
{
set_error
(
STATUS_FILE_DELETED
);
return
0
;
}
if
(
!
(
ioctl
=
create_ioctl
(
device
,
code
,
data
,
size
,
get_reply_max_size
()
)))
return
0
;
ioctl
->
thread
=
(
struct
thread
*
)
grab_object
(
current
);
ioctl
->
user_arg
=
async_data
->
arg
;
if
(
!
(
handle
=
alloc_handle
(
current
->
process
,
ioctl
,
SYNCHRONIZE
,
0
)))
{
release_object
(
ioctl
);
return
0
;
}
if
(
!
(
ioctl
->
async
=
fd_queue_async
(
device
->
fd
,
async_data
,
ASYNC_TYPE_WAIT
,
0
)))
{
close_handle
(
current
->
process
,
handle
);
release_object
(
ioctl
);
return
0
;
}
list_add_tail
(
&
device
->
requests
,
&
ioctl
->
dev_entry
);
list_add_tail
(
&
device
->
manager
->
requests
,
&
ioctl
->
mgr_entry
);
if
(
list_head
(
&
device
->
manager
->
requests
)
==
&
ioctl
->
mgr_entry
)
/* first one */
wake_up
(
&
device
->
manager
->
obj
,
0
);
/* don't release ioctl since it is now queued in the device */
set_error
(
STATUS_PENDING
);
return
handle
;
}
static
struct
device
*
create_device
(
struct
directory
*
root
,
const
struct
unicode_str
*
name
,
struct
device_manager
*
manager
,
unsigned
int
attr
)
{
...
...
@@ -153,6 +321,7 @@ static struct device *create_device( struct directory *root, const struct unicod
/* initialize it if it didn't already exist */
device
->
manager
=
manager
;
list_add_tail
(
&
manager
->
devices
,
&
device
->
entry
);
list_init
(
&
device
->
requests
);
if
(
!
(
device
->
fd
=
alloc_pseudo_fd
(
&
device_fd_ops
,
&
device
->
obj
,
0
)))
{
release_object
(
device
);
...
...
@@ -165,8 +334,16 @@ static struct device *create_device( struct directory *root, const struct unicod
static
void
delete_device
(
struct
device
*
device
)
{
struct
ioctl_call
*
ioctl
;
if
(
!
device
->
manager
)
return
;
/* already deleted */
/* terminate all pending requests */
LIST_FOR_EACH_ENTRY
(
ioctl
,
&
device
->
requests
,
struct
ioctl_call
,
dev_entry
)
{
list_remove
(
&
ioctl
->
mgr_entry
);
set_ioctl_result
(
ioctl
,
STATUS_FILE_DELETED
,
NULL
,
0
);
}
unlink_named_object
(
&
device
->
obj
);
list_remove
(
&
device
->
entry
);
device
->
manager
=
NULL
;
...
...
@@ -178,6 +355,13 @@ static void device_manager_dump( struct object *obj, int verbose )
fprintf
(
stderr
,
"Device manager
\n
"
);
}
static
int
device_manager_signaled
(
struct
object
*
obj
,
struct
thread
*
thread
)
{
struct
device_manager
*
manager
=
(
struct
device_manager
*
)
obj
;
return
!
list_empty
(
&
manager
->
requests
);
}
static
void
device_manager_destroy
(
struct
object
*
obj
)
{
struct
device_manager
*
manager
=
(
struct
device_manager
*
)
obj
;
...
...
@@ -197,6 +381,7 @@ static struct device_manager *create_device_manager(void)
if
((
manager
=
alloc_object
(
&
device_manager_ops
)))
{
list_init
(
&
manager
->
devices
);
list_init
(
&
manager
->
requests
);
}
return
manager
;
}
...
...
server/file.h
View file @
61e08b34
...
...
@@ -133,6 +133,7 @@ extern struct async *create_async( struct thread *thread, struct async_queue *qu
extern
void
async_set_timeout
(
struct
async
*
async
,
timeout_t
timeout
,
unsigned
int
status
);
extern
void
async_set_result
(
struct
object
*
obj
,
unsigned
int
status
);
extern
int
async_waiting
(
struct
async_queue
*
queue
);
extern
void
async_terminate
(
struct
async
*
async
,
unsigned
int
status
);
extern
void
async_wake_up
(
struct
async_queue
*
queue
,
unsigned
int
status
);
/* access rights that require Unix read permission */
...
...
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