PageRenderTime 51ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/server/async.c

https://github.com/perj/wine
C | 359 lines | 278 code | 51 blank | 30 comment | 61 complexity | 87038d8d492182e998b813facfdf5c82 MD5 | raw file
  1. /*
  2. * Server-side async I/O support
  3. *
  4. * Copyright (C) 2007 Alexandre Julliard
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  19. */
  20. #include <assert.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <stdarg.h>
  24. #include "ntstatus.h"
  25. #define WIN32_NO_STATUS
  26. #include "windef.h"
  27. #include "winternl.h"
  28. #include "object.h"
  29. #include "file.h"
  30. #include "request.h"
  31. struct async
  32. {
  33. struct object obj; /* object header */
  34. struct thread *thread; /* owning thread */
  35. struct list queue_entry; /* entry in async queue list */
  36. struct async_queue *queue; /* queue containing this async */
  37. unsigned int status; /* current status */
  38. struct timeout_user *timeout;
  39. unsigned int timeout_status; /* status to report upon timeout */
  40. struct event *event;
  41. async_data_t data; /* data for async I/O call */
  42. };
  43. static void async_dump( struct object *obj, int verbose );
  44. static void async_destroy( struct object *obj );
  45. static const struct object_ops async_ops =
  46. {
  47. sizeof(struct async), /* size */
  48. async_dump, /* dump */
  49. no_get_type, /* get_type */
  50. no_add_queue, /* add_queue */
  51. NULL, /* remove_queue */
  52. NULL, /* signaled */
  53. NULL, /* satisfied */
  54. no_signal, /* signal */
  55. no_get_fd, /* get_fd */
  56. no_map_access, /* map_access */
  57. default_get_sd, /* get_sd */
  58. default_set_sd, /* set_sd */
  59. no_lookup_name, /* lookup_name */
  60. no_open_file, /* open_file */
  61. no_close_handle, /* close_handle */
  62. async_destroy /* destroy */
  63. };
  64. struct async_queue
  65. {
  66. struct object obj; /* object header */
  67. struct fd *fd; /* file descriptor owning this queue */
  68. struct completion *completion; /* completion associated with a recently closed file descriptor */
  69. apc_param_t comp_key; /* completion key associated with a recently closed file descriptor */
  70. struct list queue; /* queue of async objects */
  71. };
  72. static void async_queue_dump( struct object *obj, int verbose );
  73. static void async_queue_destroy( struct object *obj );
  74. static const struct object_ops async_queue_ops =
  75. {
  76. sizeof(struct async_queue), /* size */
  77. async_queue_dump, /* dump */
  78. no_get_type, /* get_type */
  79. no_add_queue, /* add_queue */
  80. NULL, /* remove_queue */
  81. NULL, /* signaled */
  82. NULL, /* satisfied */
  83. no_signal, /* signal */
  84. no_get_fd, /* get_fd */
  85. no_map_access, /* map_access */
  86. default_get_sd, /* get_sd */
  87. default_set_sd, /* set_sd */
  88. no_lookup_name, /* lookup_name */
  89. no_open_file, /* open_file */
  90. no_close_handle, /* close_handle */
  91. async_queue_destroy /* destroy */
  92. };
  93. static inline void async_reselect( struct async *async )
  94. {
  95. if (async->queue->fd) fd_reselect_async( async->queue->fd, async->queue );
  96. }
  97. static void async_dump( struct object *obj, int verbose )
  98. {
  99. struct async *async = (struct async *)obj;
  100. assert( obj->ops == &async_ops );
  101. fprintf( stderr, "Async thread=%p\n", async->thread );
  102. }
  103. static void async_destroy( struct object *obj )
  104. {
  105. struct async *async = (struct async *)obj;
  106. assert( obj->ops == &async_ops );
  107. list_remove( &async->queue_entry );
  108. async_reselect( async );
  109. if (async->timeout) remove_timeout_user( async->timeout );
  110. if (async->event) release_object( async->event );
  111. release_object( async->queue );
  112. release_object( async->thread );
  113. }
  114. static void async_queue_dump( struct object *obj, int verbose )
  115. {
  116. struct async_queue *async_queue = (struct async_queue *)obj;
  117. assert( obj->ops == &async_queue_ops );
  118. fprintf( stderr, "Async queue fd=%p\n", async_queue->fd );
  119. }
  120. static void async_queue_destroy( struct object *obj )
  121. {
  122. struct async_queue *async_queue = (struct async_queue *)obj;
  123. assert( obj->ops == &async_queue_ops );
  124. if (async_queue->completion) release_object( async_queue->completion );
  125. }
  126. /* notifies client thread of new status of its async request */
  127. void async_terminate( struct async *async, unsigned int status )
  128. {
  129. apc_call_t data;
  130. assert( status != STATUS_PENDING );
  131. if (async->status != STATUS_PENDING)
  132. {
  133. /* already terminated, just update status */
  134. async->status = status;
  135. return;
  136. }
  137. memset( &data, 0, sizeof(data) );
  138. data.type = APC_ASYNC_IO;
  139. data.async_io.func = async->data.callback;
  140. data.async_io.user = async->data.arg;
  141. data.async_io.sb = async->data.iosb;
  142. data.async_io.status = status;
  143. thread_queue_apc( async->thread, &async->obj, &data );
  144. async->status = status;
  145. async_reselect( async );
  146. release_object( async ); /* so that it gets destroyed when the async is done */
  147. }
  148. /* callback for timeout on an async request */
  149. static void async_timeout( void *private )
  150. {
  151. struct async *async = private;
  152. async->timeout = NULL;
  153. async_terminate( async, async->timeout_status );
  154. }
  155. /* create a new async queue for a given fd */
  156. struct async_queue *create_async_queue( struct fd *fd )
  157. {
  158. struct async_queue *queue = alloc_object( &async_queue_ops );
  159. if (queue)
  160. {
  161. queue->fd = fd;
  162. queue->completion = NULL;
  163. list_init( &queue->queue );
  164. }
  165. return queue;
  166. }
  167. /* free an async queue, cancelling all async operations */
  168. void free_async_queue( struct async_queue *queue )
  169. {
  170. if (!queue) return;
  171. if (queue->fd) queue->completion = fd_get_completion( queue->fd, &queue->comp_key );
  172. queue->fd = NULL;
  173. async_wake_up( queue, STATUS_HANDLES_CLOSED );
  174. release_object( queue );
  175. }
  176. /* create an async on a given queue of a fd */
  177. struct async *create_async( struct thread *thread, struct async_queue *queue, const async_data_t *data )
  178. {
  179. struct event *event = NULL;
  180. struct async *async;
  181. if (data->event && !(event = get_event_obj( thread->process, data->event, EVENT_MODIFY_STATE )))
  182. return NULL;
  183. if (!(async = alloc_object( &async_ops )))
  184. {
  185. if (event) release_object( event );
  186. return NULL;
  187. }
  188. async->thread = (struct thread *)grab_object( thread );
  189. async->event = event;
  190. async->status = STATUS_PENDING;
  191. async->data = *data;
  192. async->timeout = NULL;
  193. async->queue = (struct async_queue *)grab_object( queue );
  194. list_add_tail( &queue->queue, &async->queue_entry );
  195. grab_object( async );
  196. if (queue->fd) set_fd_signaled( queue->fd, 0 );
  197. if (event) reset_event( event );
  198. return async;
  199. }
  200. /* set the timeout of an async operation */
  201. void async_set_timeout( struct async *async, timeout_t timeout, unsigned int status )
  202. {
  203. if (async->timeout) remove_timeout_user( async->timeout );
  204. if (timeout != TIMEOUT_INFINITE) async->timeout = add_timeout_user( timeout, async_timeout, async );
  205. else async->timeout = NULL;
  206. async->timeout_status = status;
  207. }
  208. static void add_async_completion( struct async_queue *queue, apc_param_t cvalue, unsigned int status,
  209. unsigned int information )
  210. {
  211. if (status == STATUS_MORE_PROCESSING_REQUIRED)
  212. return; /* The async callback has successfully finished but no completion should be reported */
  213. if (queue->fd)
  214. {
  215. apc_param_t ckey;
  216. struct completion *completion = fd_get_completion( queue->fd, &ckey );
  217. if (completion)
  218. {
  219. add_completion( completion, ckey, cvalue, status, information );
  220. release_object( completion );
  221. }
  222. }
  223. else if (queue->completion) add_completion( queue->completion, queue->comp_key,
  224. cvalue, status, information );
  225. }
  226. /* store the result of the client-side async callback */
  227. void async_set_result( struct object *obj, unsigned int status, unsigned int total, client_ptr_t apc )
  228. {
  229. struct async *async = (struct async *)obj;
  230. if (obj->ops != &async_ops) return; /* in case the client messed up the APC results */
  231. assert( async->status != STATUS_PENDING ); /* it must have been woken up if we get a result */
  232. if (status == STATUS_PENDING) /* restart it */
  233. {
  234. status = async->status;
  235. async->status = STATUS_PENDING;
  236. grab_object( async );
  237. if (status != STATUS_ALERTED) /* it was terminated in the meantime */
  238. async_terminate( async, status );
  239. else
  240. async_reselect( async );
  241. }
  242. else
  243. {
  244. if (async->timeout) remove_timeout_user( async->timeout );
  245. async->timeout = NULL;
  246. async->status = status;
  247. if (async->data.cvalue) add_async_completion( async->queue, async->data.cvalue, status, total );
  248. if (apc)
  249. {
  250. apc_call_t data;
  251. memset( &data, 0, sizeof(data) );
  252. data.type = APC_USER;
  253. data.user.func = apc;
  254. data.user.args[0] = async->data.arg;
  255. data.user.args[1] = async->data.iosb;
  256. data.user.args[2] = 0;
  257. thread_queue_apc( async->thread, NULL, &data );
  258. }
  259. if (async->event) set_event( async->event );
  260. else if (async->queue->fd) set_fd_signaled( async->queue->fd, 1 );
  261. }
  262. }
  263. /* check if there are any queued async operations */
  264. int async_queued( struct async_queue *queue )
  265. {
  266. return queue && list_head( &queue->queue );
  267. }
  268. /* check if an async operation is waiting to be alerted */
  269. int async_waiting( struct async_queue *queue )
  270. {
  271. struct list *ptr;
  272. struct async *async;
  273. if (!queue) return 0;
  274. if (!(ptr = list_head( &queue->queue ))) return 0;
  275. async = LIST_ENTRY( ptr, struct async, queue_entry );
  276. return async->status == STATUS_PENDING;
  277. }
  278. int async_wake_up_by( struct async_queue *queue, struct process *process,
  279. struct thread *thread, client_ptr_t iosb, unsigned int status )
  280. {
  281. struct list *ptr, *next;
  282. int woken = 0;
  283. if (!queue || (!process && !thread && !iosb)) return 0;
  284. LIST_FOR_EACH_SAFE( ptr, next, &queue->queue )
  285. {
  286. struct async *async = LIST_ENTRY( ptr, struct async, queue_entry );
  287. if ( (!process || async->thread->process == process) &&
  288. (!thread || async->thread == thread) &&
  289. (!iosb || async->data.iosb == iosb) )
  290. {
  291. async_terminate( async, status );
  292. woken++;
  293. }
  294. }
  295. return woken;
  296. }
  297. /* wake up async operations on the queue */
  298. void async_wake_up( struct async_queue *queue, unsigned int status )
  299. {
  300. struct list *ptr, *next;
  301. if (!queue) return;
  302. LIST_FOR_EACH_SAFE( ptr, next, &queue->queue )
  303. {
  304. struct async *async = LIST_ENTRY( ptr, struct async, queue_entry );
  305. async_terminate( async, status );
  306. if (status == STATUS_ALERTED) break; /* only wake up the first one */
  307. }
  308. }