source: trunk/src/kernel32/overlappedio.cpp@ 7564

Last change on this file since 7564 was 7564, checked in by sandervl, 24 years ago

overlappedio, com & lpt updates

File size: 17.9 KB
Line 
1/* $Id: overlappedio.cpp,v 1.6 2001-12-07 11:28:11 sandervl Exp $ */
2
3/*
4 * Win32 overlapped IO class
5 *
6 * Copyright 2001 Sander van Leeuwen <sandervl@xs4all.nl>
7 *
8 * Project Odin Software License can be found in LICENSE.TXT
9 *
10 */
11
12
13
14#include <os2win.h>
15#include <string.h>
16#include <handlemanager.h>
17#include <heapstring.h>
18#include "overlappedio.h"
19#include "oslibdos.h"
20
21#define DBG_LOCALLOG DBG_overlappedio
22#include "dbglocal.h"
23
24
25//******************************************************************************
26//******************************************************************************
27OverlappedIOHandler::OverlappedIOHandler(LPOVERLAPPED_HANDLER lpReadHandler,
28 LPOVERLAPPED_HANDLER lpWriteHandler,
29 LPOVERLAPPED_HANDLER lpPollHandler) :
30 hThreadRead(0), hThreadWrite(0), hThreadPoll(0)
31{
32 OverlappedIOError errcode = OutOfMemory;
33
34 if(lpReadHandler == NULL || lpPollHandler == NULL) {
35 throw(InvalidParameter);
36 }
37
38 pending[ASYNC_INDEX_READ] = pending[ASYNC_INDEX_WRITE] = pending [ASYNC_INDEX_POLL] = NULL;
39
40 this->lpReadHandler = lpReadHandler;
41 this->lpWriteHandler = lpWriteHandler;
42 this->lpPollHandler = lpPollHandler;
43
44 ::InitializeCriticalSection(&critsect);
45 //poll, read & write event semaphores are auto-reset (one thread wakes up
46 //after a SetEvent call)
47 hEventPoll = ::CreateEventA(NULL, FALSE, FALSE, NULL);
48 hEventRead = ::CreateEventA(NULL, FALSE, FALSE, NULL);
49 hEventWrite = ::CreateEventA(NULL, FALSE, FALSE, NULL);
50
51 //the exit event semaphore is manual reset, because this event
52 //must be able to wake up multiple threads
53 hEventExit = ::CreateEventA(NULL, TRUE, FALSE, NULL);
54 if(!hEventPoll || !hEventRead || !hEventWrite || !hEventExit)
55 {
56 DebugInt3();
57 errcode = EventCreationFailed;
58 goto failed;
59 }
60
61 DWORD dwThreadId;
62 LPOVERLAPPED_THREAD_PARAM threadparam;
63
64 dwAsyncType = (lpWriteHandler) ? ASYNCIO_READ : ASYNCIO_READWRITE;
65 threadparam = (LPOVERLAPPED_THREAD_PARAM)malloc(sizeof(OVERLAPPED_THREAD_PARAM));
66 if(!threadparam) goto outofmem;
67 threadparam->dwOperation = dwAsyncType;
68 threadparam->lpOverlappedObj = this;
69 hThreadRead = ::CreateThread(NULL, 32*1024, OverlappedIOThread, (LPVOID)threadparam, 0, &dwThreadId);
70
71 if(lpWriteHandler) {
72 dwAsyncType |= ASYNCIO_WRITE;
73
74 threadparam = (LPOVERLAPPED_THREAD_PARAM)malloc(sizeof(OVERLAPPED_THREAD_PARAM));
75 if(!threadparam) goto outofmem;
76 threadparam->dwOperation = ASYNCIO_WRITE;
77 threadparam->lpOverlappedObj = this;
78 hThreadWrite = ::CreateThread(NULL, 32*1024, OverlappedIOThread, (LPVOID)threadparam, 0, &dwThreadId);
79 }
80
81 if(lpPollHandler) {
82 dwAsyncType |= ASYNCIO_POLL;
83
84 threadparam = (LPOVERLAPPED_THREAD_PARAM)malloc(sizeof(OVERLAPPED_THREAD_PARAM));
85 if(!threadparam) goto outofmem;
86 threadparam->dwOperation = ASYNCIO_POLL;
87 threadparam->lpOverlappedObj = this;
88 hThreadPoll = ::CreateThread(NULL, 32*1024, OverlappedIOThread, (LPVOID)threadparam, 0, &dwThreadId);
89 }
90
91 if((lpPollHandler && !hThreadPoll) || !hThreadRead || (lpWriteHandler && !hThreadWrite))
92 {
93 DebugInt3();
94 errcode = ThreadCreationFailed;
95 goto failed;
96 }
97 return;
98
99outofmem:
100 errcode = OutOfMemory;
101 //fall through
102failed:
103 //SvL: NOTE: We might not fail gracefully when threads have already been
104 // created. (thread accessing memory that has been freed)
105 // Don't feel like wasting time to fix this as this should never
106 // happen anyway.
107 if(hEventExit) {
108 ::SetEvent(hEventExit);
109 ::CloseHandle(hEventExit);
110 }
111
112 if(hEventRead) ::CloseHandle(hEventRead);
113 if(hEventWrite) ::CloseHandle(hEventWrite);
114 if(hEventPoll) ::CloseHandle(hEventPoll);
115
116 if(hThreadRead) ::CloseHandle(hThreadRead);
117 if(hThreadPoll) ::CloseHandle(hThreadPoll);
118 if(hThreadWrite) ::CloseHandle(hThreadWrite);
119 ::DeleteCriticalSection(&critsect);
120
121 throw(errcode);
122}
123//******************************************************************************
124//******************************************************************************
125OverlappedIOHandler::~OverlappedIOHandler()
126{
127 dprintf(("~OverlappedIOHandler: signalling overlapped threads"));
128 ::SetEvent(hEventExit);
129
130 ::CloseHandle(hEventExit);
131 ::CloseHandle(hEventRead);
132 ::CloseHandle(hEventWrite);
133 ::CloseHandle(hEventPoll);
134
135 ::CloseHandle(hThreadRead);
136 if(hThreadPoll) ::CloseHandle(hThreadPoll);
137 if(hThreadWrite) ::CloseHandle(hThreadWrite);
138
139 DeleteCriticalSection(&critsect);
140}
141//******************************************************************************
142//******************************************************************************
143DWORD CALLBACK OverlappedIOThread(LPVOID lpThreadParam)
144{
145 LPOVERLAPPED_THREAD_PARAM threadparam = (LPOVERLAPPED_THREAD_PARAM)lpThreadParam;
146 DWORD dwOperation;
147 OverlappedIOHandler *lpOverlappedObj;
148
149 if(threadparam == NULL) {
150 DebugInt3();
151 return 0;
152 }
153 lpOverlappedObj = threadparam->lpOverlappedObj;
154 dwOperation = threadparam->dwOperation;
155 //free thread parameter first
156 free(threadparam);
157
158 return lpOverlappedObj->threadHandler(dwOperation);
159}
160//******************************************************************************
161//******************************************************************************
162DWORD OverlappedIOHandler::threadHandler(DWORD dwOperation)
163{
164 LPASYNCIOREQUEST lpRequest;
165 LPOVERLAPPED lpOverlapped;
166 HANDLE hEvents[2];
167 DWORD ret, dwTimeOut, dwResult;
168 int index;
169
170 dprintf(("OverlappedIOThread: started for event %d", dwOperation));
171 switch(dwOperation) {
172 case ASYNCIO_READ:
173 case ASYNCIO_READWRITE:
174 hEvents[0] = hEventRead;
175 index = ASYNC_INDEX_READ;
176 break;
177
178 case ASYNCIO_WRITE:
179 hEvents[0] = hEventWrite;
180 index = ASYNC_INDEX_WRITE;
181 break;
182
183 case ASYNCIO_POLL:
184 hEvents[0] = hEventPoll;
185 index = ASYNC_INDEX_POLL;
186 break;
187 default:
188 DebugInt3();
189 }
190 hEvents[1] = hEventExit;
191
192 while(TRUE) {
193 ret = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);
194 if(ret == WAIT_FAILED) {
195 dprintf(("!WARNING!: WaitForMultipleObjects -> WAIT_FAILED!"));
196 break;
197 }
198 if(ret == WAIT_FAILED) {
199 dprintf(("!WARNING!: WaitForMultipleObjects -> WAIT_FAILED!"));
200 break;
201 }
202 //if hEventExit has been signalled, then we are told to exit
203 if(ret == (WAIT_OBJECT_0+1)) {
204 dprintf(("end of threadHandler signalled"));
205 break;
206 }
207 ::EnterCriticalSection(&critsect);
208 if(pending[index] == NULL) {
209 //oh, oh
210 ::LeaveCriticalSection(&critsect);
211 dprintf(("!ERROR!: overlapped thread woken up, but no tasks pending!!"));
212 DebugInt3();
213 continue;
214 }
215 lpRequest = pending[index];
216 pending[index] = lpRequest->next;
217 lpRequest->next = NULL;
218 ::LeaveCriticalSection(&critsect);
219
220 lpOverlapped = lpRequest->lpOverlapped;;
221
222 switch(dwOperation) {
223 case ASYNCIO_READ:
224 case ASYNCIO_READWRITE:
225 lpReadHandler(lpRequest, &dwResult, NULL);
226 lpOverlapped->Internal = lpRequest->dwLastError;
227 lpOverlapped->InternalHigh = dwResult;
228 if(lpRequest->lpdwResult) {
229 *lpRequest->lpdwResult = dwResult;
230 }
231 //wake up user thread
232 ::SetEvent(lpOverlapped->hEvent);
233 delete lpRequest;
234 break;
235
236 case ASYNCIO_WRITE:
237 lpWriteHandler(lpRequest, &dwResult, NULL);
238 lpOverlapped->Internal = lpRequest->dwLastError;
239 lpOverlapped->InternalHigh = dwResult;
240 if(lpRequest->lpdwResult) {
241 *lpRequest->lpdwResult = dwResult;
242 }
243 //wake up user thread
244 ::SetEvent(lpOverlapped->hEvent);
245 delete lpRequest;
246 break;
247
248 case ASYNCIO_POLL:
249 while(TRUE)
250 {
251 dwTimeOut = 0;
252 if(lpPollHandler(lpRequest, &dwResult, &dwTimeOut) == TRUE) {
253 break;
254 }
255 if(dwTimeOut == 0) {
256 dprintf(("!ERROR!: lpPollHandler returned timeout 0!!"));
257 DebugInt3();
258 break;
259 }
260 Sleep(dwTimeOut);
261 }
262 lpOverlapped->Internal = lpRequest->dwLastError;
263 lpOverlapped->InternalHigh = dwResult;
264 if(lpRequest->lpdwResult) {
265 *lpRequest->lpdwResult = dwResult;
266 }
267 //wake up user thread
268 ::SetEvent(lpOverlapped->hEvent);
269 delete lpRequest;
270 break;
271 }
272 }
273 return 0;
274}
275//******************************************************************************
276//******************************************************************************
277BOOL OverlappedIOHandler::WriteFile(HANDLE hHandle,
278 LPCVOID lpBuffer,
279 DWORD nNumberOfBytesToWrite,
280 LPDWORD lpNumberOfBytesWritten,
281 LPOVERLAPPED lpOverlapped,
282 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
283 DWORD dwUserData,
284 DWORD dwTimeOut)
285{
286 LPASYNCIOREQUEST lpRequest, current;
287 int index;
288
289 if(!lpOverlapped || lpOverlapped->hEvent == 0) {
290 ::SetLastError(ERROR_INVALID_PARAMETER);
291 return FALSE;
292 }
293
294 lpRequest = new ASYNCIOREQUEST;
295 if(lpRequest == NULL) {
296 ::SetLastError(ERROR_NOT_ENOUGH_MEMORY);
297 return FALSE;
298 }
299 lpRequest->dwAsyncType = ASYNCIO_WRITE;
300 lpRequest->hHandle = hHandle;
301 lpRequest->lpBuffer = lpBuffer;
302 lpRequest->nNumberOfBytes = nNumberOfBytesToWrite;
303 lpRequest->lpdwResult = lpNumberOfBytesWritten;
304 lpRequest->lpOverlapped = lpOverlapped;
305 lpRequest->lpCompletionRoutine = lpCompletionRoutine;
306 lpRequest->dwUserData = dwUserData;
307 lpRequest->dwTimeOut = dwTimeOut;
308 lpRequest->next = NULL;
309
310 if(dwAsyncType == ASYNCIO_READWRITE) {
311 index = ASYNC_INDEX_READ;
312 }
313 else index = ASYNC_INDEX_WRITE;
314
315 ::EnterCriticalSection(&critsect);
316 if(pending[index]) {
317 current = pending[index];
318 while(current->next) {
319 current = current->next;
320 }
321 current->next = lpRequest;
322 }
323 else pending[index] = lpRequest;
324 ::LeaveCriticalSection(&critsect);
325
326 lpOverlapped->Internal = ERROR_IO_PENDING;
327 lpOverlapped->InternalHigh = 0;
328 lpOverlapped->Offset = 0;
329 lpOverlapped->OffsetHigh = 0;
330 //reset overlapped semaphore to non-signalled
331 ::ResetEvent(lpOverlapped->hEvent);
332
333 //wake up async thread
334 ::SetEvent((dwAsyncType == ASYNCIO_READWRITE) ? hEventRead : hEventWrite);
335
336 ::SetLastError(ERROR_IO_PENDING);
337 return FALSE;
338}
339//******************************************************************************
340//******************************************************************************
341BOOL OverlappedIOHandler::ReadFile(HANDLE hHandle,
342 LPCVOID lpBuffer,
343 DWORD nNumberOfBytesToRead,
344 LPDWORD lpNumberOfBytesRead,
345 LPOVERLAPPED lpOverlapped,
346 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
347 DWORD dwUserData,
348 DWORD dwTimeOut)
349{
350 LPASYNCIOREQUEST lpRequest, current;
351
352 if(!lpOverlapped || lpOverlapped->hEvent == 0) {
353 ::SetLastError(ERROR_INVALID_PARAMETER);
354 return FALSE;
355 }
356
357 lpRequest = new ASYNCIOREQUEST;
358 if(lpRequest == NULL) {
359 ::SetLastError(ERROR_NOT_ENOUGH_MEMORY);
360 return FALSE;
361 }
362 lpRequest->dwAsyncType = ASYNCIO_READ;
363 lpRequest->hHandle = hHandle;
364 lpRequest->lpBuffer = lpBuffer;
365 lpRequest->nNumberOfBytes = nNumberOfBytesToRead;
366 lpRequest->lpdwResult = lpNumberOfBytesRead;
367 lpRequest->lpOverlapped = lpOverlapped;
368 lpRequest->lpCompletionRoutine = lpCompletionRoutine;
369 lpRequest->dwUserData = dwUserData;
370 lpRequest->dwTimeOut = dwTimeOut;
371 lpRequest->next = NULL;
372
373 ::EnterCriticalSection(&critsect);
374 if(pending[ASYNC_INDEX_READ]) {
375 current = pending[ASYNC_INDEX_READ];
376 while(current->next) {
377 current = current->next;
378 }
379 current->next = lpRequest;
380 }
381 else pending[ASYNC_INDEX_READ] = lpRequest;
382 ::LeaveCriticalSection(&critsect);
383
384 lpOverlapped->Internal = ERROR_IO_PENDING;
385 lpOverlapped->InternalHigh = 0;
386 lpOverlapped->Offset = 0;
387 lpOverlapped->OffsetHigh = 0;
388 //reset overlapped semaphore to non-signalled
389 ::ResetEvent(lpOverlapped->hEvent);
390
391 //wake up async thread
392 ::SetEvent(hEventRead);
393 ::SetLastError(ERROR_IO_PENDING);
394 return FALSE;
395}
396//******************************************************************************
397//******************************************************************************
398BOOL OverlappedIOHandler::WaitForEvent(HANDLE hHandle,
399 LPDWORD lpfdwEvtMask,
400 LPOVERLAPPED lpOverlapped,
401 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
402 DWORD dwUserData,
403 DWORD dwTimeOut)
404{
405 LPASYNCIOREQUEST lpRequest, current;
406
407 if(!lpOverlapped || lpOverlapped->hEvent == 0) {
408 ::SetLastError(ERROR_INVALID_PARAMETER);
409 return FALSE;
410 }
411
412 lpRequest = new ASYNCIOREQUEST;
413 if(lpRequest == NULL) {
414 ::SetLastError(ERROR_NOT_ENOUGH_MEMORY);
415 return FALSE;
416 }
417 lpRequest->dwAsyncType = ASYNCIO_POLL;
418 lpRequest->hHandle = hHandle;
419 lpRequest->lpBuffer = NULL;
420 lpRequest->nNumberOfBytes = 0;
421 lpRequest->lpdwResult = lpfdwEvtMask;
422 lpRequest->lpOverlapped = lpOverlapped;
423 lpRequest->lpCompletionRoutine = lpCompletionRoutine;
424 lpRequest->dwUserData = dwUserData;
425 lpRequest->dwTimeOut = dwTimeOut;
426 lpRequest->next = NULL;
427
428 ::EnterCriticalSection(&critsect);
429 if(pending[ASYNC_INDEX_POLL]) {
430 current = pending[ASYNC_INDEX_READ];
431 while(current->next) {
432 current = current->next;
433 }
434 current->next = lpRequest;
435 }
436 else pending[ASYNC_INDEX_POLL] = lpRequest;
437 ::LeaveCriticalSection(&critsect);
438
439 lpOverlapped->Internal = ERROR_IO_PENDING;
440 lpOverlapped->InternalHigh = 0;
441 lpOverlapped->Offset = 0;
442 lpOverlapped->OffsetHigh = 0;
443 //reset overlapped semaphore to non-signalled
444 ::ResetEvent(lpOverlapped->hEvent);
445
446 //wake up async thread
447 ::SetEvent(hEventPoll);
448 ::SetLastError(ERROR_IO_PENDING);
449 return FALSE;
450}
451//******************************************************************************
452//******************************************************************************
453BOOL OverlappedIOHandler::CancelIo(HANDLE hHandle)
454{
455 LPASYNCIOREQUEST lpRequest;
456
457 for(int i=ASYNC_INDEX_READ;i<NR_ASYNC_OPERATIONS;i++)
458 {
459 while(TRUE) {
460 lpRequest = findAndRemoveRequest(i, hHandle);
461 if(lpRequest) {
462 delete lpRequest;
463 }
464 else break;
465 }
466 }
467 //TODO: return error if there were no pending requests???
468 ::SetLastError(ERROR_SUCCESS);
469 return TRUE;
470}
471//******************************************************************************
472//******************************************************************************
473BOOL OverlappedIOHandler::GetOverlappedResult(HANDLE hHandle,
474 LPOVERLAPPED lpOverlapped,
475 LPDWORD lpcbTransfer,
476 BOOL fWait)
477{
478 DWORD ret;
479
480 ret = ::WaitForSingleObject(lpOverlapped->hEvent, (fWait) ? INFINITE : 0);
481
482 if(lpcbTransfer)
483 *lpcbTransfer = lpOverlapped->InternalHigh;
484
485 ::SetLastError(lpOverlapped->Internal);
486
487 return (ret == WAIT_OBJECT_0);
488}
489//******************************************************************************
490//******************************************************************************
491LPASYNCIOREQUEST OverlappedIOHandler::findAndRemoveRequest(int index, HANDLE hHandle)
492{
493 LPASYNCIOREQUEST lpRequest, lpFound = NULL;
494
495 ::EnterCriticalSection(&critsect);
496 if(pending[index])
497 {
498 if(pending[index]->hHandle != hHandle)
499 {
500 lpRequest = pending[index];
501 while(lpRequest->next) {
502 if(lpRequest->next->hHandle == hHandle) {
503 lpFound = lpRequest->next;
504 lpRequest->next = lpFound->next;
505 break;
506 }
507 lpRequest = lpRequest->next;
508 }
509 }
510 else {
511 lpFound = pending[index];
512 pending[index] = lpFound->next;
513 }
514 }
515 ::LeaveCriticalSection(&critsect);
516 return lpFound;
517}
518//******************************************************************************
519//******************************************************************************
Note: See TracBrowser for help on using the repository browser.