Mercurial > ecos
changeset 2686:1a5b0e64f79a
* src/fd.cxx (fp_ucount_dec, fd_close): Fix locking strategy so
that the fdlock is free when filesystem close entry is
called. This allows other threads to peform descriptor operations
during the close.
| author | nickg |
|---|---|
| date | Fri, 12 Dec 2008 10:50:43 +0000 |
| parents | 1a4560795b04 |
| children | e78db9cb95db |
| files | packages/io/fileio/current/ChangeLog packages/io/fileio/current/src/fd.cxx |
| diffstat | 2 files changed, 31 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/io/fileio/current/ChangeLog +++ b/packages/io/fileio/current/ChangeLog @@ -1,3 +1,10 @@ +2008-12-11 Nick Garnett <nickg@ecoscentric.com> + + * src/fd.cxx (fp_ucount_dec, fd_close): Fix locking strategy so + that the fdlock is free when filesystem close entry is + called. This allows other threads to peform descriptor operations + during the close. + 2008-04-02 Xinghua Yang <yxinghua@sunnorth.com.cn> Andrew Lunn <andrew.lunn@ascom.ch>
--- a/packages/io/fileio/current/src/fd.cxx +++ b/packages/io/fileio/current/src/fd.cxx @@ -149,6 +149,26 @@ static cyg_file *desc[CYGNUM_FILEIO_NFD] //-------------------------------------------------------------------------- // Decrement the use count on a file object and if it goes to zero, // close the file and deallocate the file object. +// +// A word on locking here: It is necessary for the filesystem +// fo_close() function to be called with the file lock claimed, but +// the fdlock released, to permit other threads to perform fd-related +// operations. The original code here took the file lock and released +// the fdlock before the call and then locked the fdlock and released +// the file lock after. The idea was that there was no point at which +// a lock of some sort was not held. However, if two threads are +// running through this code simultaneously, this could lead to +// deadlock, particularly if the filesystem's syncmode specifies fstab +// or mtab level locking. So the code now unlocks the file lock before +// reclaiming the fdlock. This leaves a small window where no locks +// are held, where in theory some other thread could jump in and mess +// things up. However, this is benign; if the other thread is +// accessing some other file object there will be no conflict and by +// definition no other thread can access this file object since we are +// executing here because no file descriptors point to this file +// object any longer. Additionally, the file object is only marked +// free, by zeroing the f_flag field, once the fdlock has been +// reclaimed. static int fp_ucount_dec( cyg_file *fp ) { @@ -156,13 +176,14 @@ static int fp_ucount_dec( cyg_file *fp ) if( (--fp->f_ucount) <= 0 ) { cyg_file_lock( fp, fp->f_syncmode ); + FILEIO_MUTEX_UNLOCK(fdlock); error = fp->f_ops->fo_close(fp); cyg_file_unlock( fp, fp->f_syncmode ); + FILEIO_MUTEX_LOCK(fdlock); - if( error == 0 ) - fp->f_flag = 0; + fp->f_flag = 0; } return error; @@ -180,6 +201,7 @@ static int fd_close( int fd ) CYG_ASSERT(((0 <= fd) && (fd<CYGNUM_FILEIO_NFD)), "fd out of range"); fp = desc[fd]; + desc[fd] = FD_ALLOCATED; if( fp != FD_ALLOCATED && fp != NULL) { @@ -189,8 +211,6 @@ static int fd_close( int fd ) error = fp_ucount_dec( fp ); } - desc[fd] = FD_ALLOCATED; - return error; }
