diff options
Diffstat (limited to 'cpukit/libcsupport/src/close.c')
-rw-r--r-- | cpukit/libcsupport/src/close.c | 41 |
1 files changed, 37 insertions, 4 deletions
diff --git a/cpukit/libcsupport/src/close.c b/cpukit/libcsupport/src/close.c index 7eaeb64fea..d478e231c6 100644 --- a/cpukit/libcsupport/src/close.c +++ b/cpukit/libcsupport/src/close.c @@ -24,12 +24,45 @@ int close( int fd ) { - rtems_libio_t *iop; - int rc; + rtems_libio_t *iop; + unsigned int flags; + int rc; - LIBIO_GET_IOP( fd, iop ); + if ( (uint32_t) fd >= rtems_libio_number_iops ) { + rtems_set_errno_and_return_minus_one( EBADF ); + } - rtems_libio_iop_flags_clear( iop, LIBIO_FLAGS_OPEN ); + iop = rtems_libio_iop( fd ); + flags = rtems_libio_iop_flags( iop ); + + while ( true ) { + unsigned int desired; + bool success; + + if ( ( flags & LIBIO_FLAGS_OPEN ) == 0 ) { + rtems_set_errno_and_return_minus_one( EBADF ); + } + + /* The expected flags */ + flags &= LIBIO_FLAGS_REFERENCE_INC - 1U; + + desired = flags & ~LIBIO_FLAGS_OPEN; + success = _Atomic_Compare_exchange_uint( + &iop->flags, + &flags, + desired, + ATOMIC_ORDER_ACQ_REL, + ATOMIC_ORDER_RELAXED + ); + + if ( success ) { + break; + } + + if ( ( flags & ~( LIBIO_FLAGS_REFERENCE_INC - 1U ) ) != 0 ) { + rtems_set_errno_and_return_minus_one( EBUSY ); + } + } rc = (*iop->pathinfo.handlers->close_h)( iop ); |