From 0c8731b8f43ff50700432767b34e67a11a713bff Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Mon, 19 Apr 2004 19:29:10 +0000 Subject: * errno.cc (errmap): Handle ERROR_IO_PENDING. * fhandler.cc (fhandler_base::open): Make tape I/O asynchronous. * fhandler.h (class fhandler_dev_tape): Add mt_evt member. * fhandler_tape.cc (mtinfo_drive::initialize): Initialize async_writes. (mtinfo_drive::close): Handle async writes. (mtinfo_drive::read): Add mt_evt parameter. Use overlapped I/O. (mtinfo_drive::async_wait): New function. (mtinfo_drive::write): Add mt_evt parameter. Use overlapped I/O. Handle async writes. (mtinfo_drive::_set_pos): Handle async writes. (mtinfo_drive::set_partition): Ditto. (mtinfo_drive::prepare): Ditto. (mtinfo_drive::get_status): Drop useless "else". Handle async_writes flag. (mtinfo_drive::set_options): Handle async_writes flags. (fhandler_dev_tape::close): Close mt_evt handle. (fhandler_dev_tape::raw_read): Create mt_evt handle and use in call to mtinfo_drive::read. (fhandler_dev_tape::raw_write): Create mt_evt handle and use in call to mtinfo_drive::write. * mtinfo.h (MTINFO_VERSION): Bump. (enum dirty_state): Add async_write_pending state. (class mtinfo_drive): Add OVERLAPPED struct "ov". Add async_writes flag. (mtinfo_drive::async_wait): Add declaration. (mtinfo_drive::read): Add mt_evt parameter. (mtinfo_drive::write): Ditto. * registry.cc (load_registry_hive): Call enable_restore_privilege instead of set_process_privilege. --- winsup/cygwin/ChangeLog | 33 ++++++++++++++ winsup/cygwin/errno.cc | 1 + winsup/cygwin/fhandler.cc | 3 +- winsup/cygwin/fhandler.h | 1 + winsup/cygwin/fhandler_tape.cc | 100 ++++++++++++++++++++++++++++++++++------- winsup/cygwin/mtinfo.h | 13 ++++-- winsup/cygwin/registry.cc | 2 +- 7 files changed, 130 insertions(+), 23 deletions(-) (limited to 'winsup') diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 2d6d8af..7870c32 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,5 +1,38 @@ 2004-04-19 Corinna Vinschen + * errno.cc (errmap): Handle ERROR_IO_PENDING. + * fhandler.cc (fhandler_base::open): Make tape I/O asynchronous. + * fhandler.h (class fhandler_dev_tape): Add mt_evt member. + * fhandler_tape.cc (mtinfo_drive::initialize): Initialize async_writes. + (mtinfo_drive::close): Handle async writes. + (mtinfo_drive::read): Add mt_evt parameter. Use overlapped I/O. + (mtinfo_drive::async_wait): New function. + (mtinfo_drive::write): Add mt_evt parameter. Use overlapped I/O. + Handle async writes. + (mtinfo_drive::_set_pos): Handle async writes. + (mtinfo_drive::set_partition): Ditto. + (mtinfo_drive::prepare): Ditto. + (mtinfo_drive::get_status): Drop useless "else". Handle async_writes + flag. + (mtinfo_drive::set_options): Handle async_writes flags. + (fhandler_dev_tape::close): Close mt_evt handle. + (fhandler_dev_tape::raw_read): Create mt_evt handle and use in call + to mtinfo_drive::read. + (fhandler_dev_tape::raw_write): Create mt_evt handle and use in call + to mtinfo_drive::write. + * mtinfo.h (MTINFO_VERSION): Bump. + (enum dirty_state): Add async_write_pending state. + (class mtinfo_drive): Add OVERLAPPED struct "ov". Add async_writes + flag. + (mtinfo_drive::async_wait): Add declaration. + (mtinfo_drive::read): Add mt_evt parameter. + (mtinfo_drive::write): Ditto. + + * registry.cc (load_registry_hive): Call enable_restore_privilege + instead of set_process_privilege. + +2004-04-19 Corinna Vinschen + * fhandler_tape.cc (mtinfo_drive::_set_pos): Take additional dont_wait parameter. Use in call to SetTapePosition. (mtinfo_drive::set_pos): Accomodate _set_pos calls to above change. diff --git a/winsup/cygwin/errno.cc b/winsup/cygwin/errno.cc index 475164a..7d99f75 100644 --- a/winsup/cygwin/errno.cc +++ b/winsup/cygwin/errno.cc @@ -119,6 +119,7 @@ static NO_COPY struct X (NO_MEDIA_IN_DRIVE, ENOMEDIUM), X (DEVICE_REQUIRES_CLEANING, EIO), X (DEVICE_DOOR_OPEN, EIO), + X (IO_PENDING, EAGAIN), { 0, NULL, 0} }; diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index f1dfed8..a3ef1bb 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -610,7 +610,8 @@ fhandler_base::open (int flags, mode_t mode) /* Allow reliable lseek on disk devices. */ if (get_major () == DEV_FLOPPY_MAJOR) access |= GENERIC_READ; - else if (get_major () != DEV_SERIAL_MAJOR) + else if (get_major () != DEV_SERIAL_MAJOR + && get_major () != DEV_TAPE_MAJOR) { create_options |= FILE_SYNCHRONOUS_IO_NONALERT; access |= SYNCHRONIZE; diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 17f3ade..9903864 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -535,6 +535,7 @@ class fhandler_dev_floppy: public fhandler_dev_raw class fhandler_dev_tape: public fhandler_dev_raw { HANDLE mt_mtx; + HANDLE mt_evt; bool is_rewind_device () { return get_minor () < 128; } unsigned int driveno () { return (unsigned int) get_minor () & 0x7f; } diff --git a/winsup/cygwin/fhandler_tape.cc b/winsup/cygwin/fhandler_tape.cc index 0f3ed0e..2296d59 100644 --- a/winsup/cygwin/fhandler_tape.cc +++ b/winsup/cygwin/fhandler_tape.cc @@ -81,6 +81,7 @@ mtinfo_drive::initialize (int num, bool first_time) if (first_time) { buffer_writes (true); + async_writes (false); two_fm (false); fast_eom (false); auto_lock (false); @@ -135,16 +136,22 @@ mtinfo_drive::close (HANDLE mt, bool rewind) lasterr = 0; if (GetTapeStatus (mt) == ERROR_NO_MEDIA_IN_DRIVE) dirty = clean; - if (dirty == has_written) + if (dirty >= has_written) { - /* if last operation was writing, write a filemark */ - debug_printf ("writing filemark"); - write_marks (mt, TAPE_FILEMARKS, two_fm () ? 2 : 1); - if (two_fm () && !lasterr && !rewind) /* Backspace over 2nd filemark. */ + /* If an async write is still pending, wait for completion. */ + if (dirty == async_write_pending) + lasterr = async_wait (mt, NULL); + if (!lasterr) { - set_pos (mt, TAPE_SPACE_FILEMARKS, -1, false); - if (!lasterr) - part (partition)->fblock = 0; /* That's obvious, isn't it? */ + /* if last operation was writing, write a filemark */ + debug_printf ("writing filemark"); + write_marks (mt, TAPE_FILEMARKS, two_fm () ? 2 : 1); + if (two_fm () && !lasterr && !rewind) /* Backspace over 2nd fmark. */ + { + set_pos (mt, TAPE_SPACE_FILEMARKS, -1, false); + if (!lasterr) + part (partition)->fblock = 0; /* That's obvious, isn't it? */ + } } } else if (dirty == has_read && !rewind) @@ -179,7 +186,7 @@ mtinfo_drive::close (HANDLE mt, bool rewind) } int -mtinfo_drive::read (HANDLE mt, void *ptr, size_t &ulen) +mtinfo_drive::read (HANDLE mt, HANDLE mt_evt, void *ptr, size_t &ulen) { BOOL ret; DWORD bytes_read = 0; @@ -191,6 +198,9 @@ mtinfo_drive::read (HANDLE mt, void *ptr, size_t &ulen) ulen = 0; goto out; } + /* If an async write is still pending, wait for completion. */ + if (dirty == async_write_pending) + lasterr = async_wait (mt, NULL); dirty = clean; if (part (partition)->emark == eof_hit) { @@ -225,8 +235,12 @@ mtinfo_drive::read (HANDLE mt, void *ptr, size_t &ulen) part (partition)->smark = false; if (auto_lock () && lock < auto_locked) prepare (mt, TAPE_LOCK, true); - ret = ReadFile (mt, ptr, ulen, &bytes_read, 0); + ov.Offset = ov.OffsetHigh = 0; + ov.hEvent = mt_evt; + ret = ReadFile (mt, ptr, ulen, &bytes_read, &ov); lasterr = ret ? 0 : GetLastError (); + if (lasterr == ERROR_IO_PENDING) + lasterr = async_wait (mt, &bytes_read); ulen = (size_t) bytes_read; if (bytes_read > 0) { @@ -273,10 +287,22 @@ out: } int -mtinfo_drive::write (HANDLE mt, const void *ptr, size_t &len) +mtinfo_drive::async_wait (HANDLE mt, DWORD *bytes_written) +{ + DWORD written; + + bool ret = GetOverlappedResult (mt, &ov, &written, TRUE); + if (bytes_written) + *bytes_written = written; + return ret ? 0 : GetLastError (); +} + +int +mtinfo_drive::write (HANDLE mt, HANDLE mt_evt, const void *ptr, size_t &len) { BOOL ret; DWORD bytes_written = 0; + int async_err = 0; if (GetTapeStatus (mt) == ERROR_NO_MEDIA_IN_DRIVE) return lasterr = ERROR_NO_MEDIA_IN_DRIVE; @@ -285,12 +311,24 @@ mtinfo_drive::write (HANDLE mt, const void *ptr, size_t &len) len = 0; return error ("write"); } + if (dirty == async_write_pending) + async_err = async_wait (mt, &bytes_written); dirty = clean; part (partition)->smark = false; if (auto_lock () && lock < auto_locked) prepare (mt, TAPE_LOCK, true); - ret = WriteFile (mt, ptr, len, &bytes_written, 0); + ov.Offset = ov.OffsetHigh = 0; + ov.hEvent = mt_evt; + ret = WriteFile (mt, ptr, len, &bytes_written, &ov); lasterr = ret ? 0: GetLastError (); + if (lasterr == ERROR_IO_PENDING) + { + if (async_writes () && mp ()->BlockSize == 0) + dirty = async_write_pending; + else + /* Wait for completion if a non-async write. */ + lasterr = async_wait (mt, &bytes_written); + } len = (size_t) bytes_written; if (bytes_written > 0) { @@ -301,6 +339,8 @@ mtinfo_drive::write (HANDLE mt, const void *ptr, size_t &len) if (part (partition)->fblock >= 0) part (partition)->fblock += blocks_written; } + if (!lasterr && async_err) + lasterr = async_err; if (lasterr == ERROR_EOM_OVERFLOW) part (partition)->emark = eom; else if (lasterr == ERROR_END_OF_MEDIA) @@ -310,6 +350,8 @@ mtinfo_drive::write (HANDLE mt, const void *ptr, size_t &len) part (partition)->emark = no_eof; if (!lasterr) dirty = has_written; + else if (lasterr == ERROR_IO_PENDING) + dirty = async_write_pending; } return error ("write"); } @@ -344,9 +386,12 @@ int mtinfo_drive::_set_pos (HANDLE mt, int mode, long count, int partition, BOOL dont_wait) { + /* If an async write is still pending, wait for completion. */ + if (dirty == async_write_pending) + lasterr = async_wait (mt, NULL); + dirty = clean; TAPE_FUNC (SetTapePosition (mt, mode, partition, count, count < 0 ? -1 : 0, dont_wait)); - dirty = clean; return lasterr; } @@ -575,6 +620,12 @@ mtinfo_drive::set_partition (HANDLE mt, long count) int mtinfo_drive::write_marks (HANDLE mt, int marktype, DWORD count) { + /* If an async write is still pending, wait for completion. */ + if (dirty == async_write_pending) + { + lasterr = async_wait (mt, NULL); + dirty = has_written; + } if (marktype != TAPE_SETMARKS) dirty = clean; if (marktype == TAPE_FILEMARKS @@ -639,6 +690,9 @@ mtinfo_drive::prepare (HANDLE mt, int action, bool is_auto) { BOOL dont_wait = FALSE; + /* If an async write is still pending, wait for completion. */ + if (dirty == async_write_pending) + lasterr = async_wait (mt, NULL); dirty = clean; if (action == TAPE_UNLOAD || action == TAPE_LOAD || action == TAPE_TENSION) dont_wait = nowait () ? TRUE : FALSE; @@ -781,7 +835,7 @@ mtinfo_drive::get_status (HANDLE mt, struct mtget *get) if (buffer_writes ()) get->mt_gstat |= GMT_IM_REP_EN (-1); /* TODO: Async writes */ - else if (tstat == ERROR_DEVICE_REQUIRES_CLEANING) + if (tstat == ERROR_DEVICE_REQUIRES_CLEANING) get->mt_gstat |= GMT_CLN (-1); /* Cygwin specials: */ @@ -803,6 +857,8 @@ mtinfo_drive::get_status (HANDLE mt, struct mtget *get) get->mt_gstat |= GMT_SYSV (-1); if (nowait ()) get->mt_gstat |= GMT_NOWAIT (-1); + if (async_writes ()) + get->mt_gstat |= GMT_ASYNC (-1); get->mt_erreg = 0; /* FIXME: No softerr counting */ @@ -842,6 +898,7 @@ mtinfo_drive::set_options (HANDLE mt, long options) break; case MT_ST_BOOLEANS: buffer_writes (!!(options & MT_ST_BUFFER_WRITES)); + async_writes (!!(options & MT_ST_ASYNC_WRITES)); two_fm (!!(options & MT_ST_TWO_FM)); fast_eom (!!(options & MT_ST_FAST_MTEOM)); auto_lock (!!(options & MT_ST_AUTO_LOCK)); @@ -862,6 +919,8 @@ mtinfo_drive::set_options (HANDLE mt, long options) set = (what == MT_ST_SETBOOLEANS); if (options & MT_ST_BUFFER_WRITES) buffer_writes (set); + if (options & MT_ST_ASYNC_WRITES) + async_writes (set); if (options & MT_ST_TWO_FM) two_fm (set); if (options & MT_ST_FAST_MTEOM) @@ -1197,6 +1256,8 @@ fhandler_dev_tape::close (void) lock (-1); ret = mt->drive (driveno ())->close (get_handle (), is_rewind_device ()); + if (mt_evt) + CloseHandle (mt_evt); if (ret) __seterrno_from_win_error (ret); cret = fhandler_dev_raw::close (); @@ -1245,12 +1306,15 @@ fhandler_dev_tape::raw_read (void *ptr, size_t &ulen) } if (len > 0) { + if (!mt_evt && !(mt_evt = CreateEvent (&sec_none, TRUE, FALSE, NULL))) + debug_printf ("Creating event failed: %E"); size_t block_fit = !block_size ? len : rounddown(len, block_size); if (block_fit) { debug_printf ("read %d bytes from tape (rest %d)", block_fit, len - block_fit); - ret = mt->drive (driveno ())->read (get_handle (), buf, block_fit); + ret = mt->drive (driveno ())->read (get_handle (), mt_evt, buf, + block_fit); if (ret) __seterrno_from_win_error (ret); else if (block_fit) @@ -1271,7 +1335,7 @@ fhandler_dev_tape::raw_read (void *ptr, size_t &ulen) if (!ret && len > 0) { debug_printf ("read %d bytes from tape (one block)", block_size); - ret = mt->drive (driveno ())->read (get_handle (), devbuf, + ret = mt->drive (driveno ())->read (get_handle (), mt_evt, devbuf, block_size); if (ret) __seterrno_from_win_error (ret); @@ -1297,7 +1361,9 @@ int fhandler_dev_tape::raw_write (const void *ptr, size_t len) { lock (-1); - int ret = mt->drive (driveno ())->write (get_handle (), ptr, len); + if (!mt_evt && !(mt_evt = CreateEvent (&sec_none, TRUE, FALSE, NULL))) + debug_printf ("Creating event failed: %E"); + int ret = mt->drive (driveno ())->write (get_handle (), mt_evt, ptr, len); __seterrno_from_win_error (ret); return unlock (len); } diff --git a/winsup/cygwin/mtinfo.h b/winsup/cygwin/mtinfo.h index 4cf92bc..52dd6b2 100644 --- a/winsup/cygwin/mtinfo.h +++ b/winsup/cygwin/mtinfo.h @@ -9,7 +9,7 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #define MTINFO_MAGIC 0x179b2af0 -#define MTINFO_VERSION 1 +#define MTINFO_VERSION 2 /* Maximum number of supported partitions per drive. */ #define MAX_PARTITION_NUM 64 @@ -33,7 +33,8 @@ enum dirty_state { clean, has_read, - has_written + has_written, + async_write_pending }; enum lock_state @@ -67,9 +68,11 @@ class mtinfo_drive lock_state lock; TAPE_GET_DRIVE_PARAMETERS _dp; TAPE_GET_MEDIA_PARAMETERS _mp; + OVERLAPPED ov; struct status_flags { unsigned buffer_writes : 1; + unsigned async_writes : 1; unsigned two_fm : 1; unsigned fast_eom : 1; unsigned auto_lock : 1; @@ -101,6 +104,7 @@ class mtinfo_drive int set_blocksize (HANDLE mt, long count); int get_status (HANDLE mt, struct mtget *get); int set_options (HANDLE mt, long options); + int async_wait (HANDLE mt, DWORD *bytes_written); public: void initialize (int num, bool first_time); @@ -108,12 +112,13 @@ public: int get_mp (HANDLE mt); int open (HANDLE mt); int close (HANDLE mt, bool rewind); - int read (HANDLE mt, void *ptr, size_t &ulen); - int write (HANDLE mt, const void *ptr, size_t &len); + int read (HANDLE mt, HANDLE mt_evt, void *ptr, size_t &ulen); + int write (HANDLE mt, HANDLE mt_evt, const void *ptr, size_t &len); int ioctl (HANDLE mt, unsigned int cmd, void *buf); int set_pos (HANDLE mt, int mode, long count, bool sfm_func); IMPLEMENT_STATUS_FLAG (bool, buffer_writes) + IMPLEMENT_STATUS_FLAG (bool, async_writes) IMPLEMENT_STATUS_FLAG (bool, two_fm) IMPLEMENT_STATUS_FLAG (bool, fast_eom) IMPLEMENT_STATUS_FLAG (bool, auto_lock) diff --git a/winsup/cygwin/registry.cc b/winsup/cygwin/registry.cc index 0a36b3a..bb47c48 100644 --- a/winsup/cygwin/registry.cc +++ b/winsup/cygwin/registry.cc @@ -241,7 +241,7 @@ load_registry_hive (PSID psid) RegCloseKey (hkey); return; } - set_process_privilege (SE_RESTORE_NAME); + enable_restore_privilege (); if (get_registry_hive_path (psid, path)) { strcat (path, "\\NTUSER.DAT"); -- cgit v1.1