OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [io/] [fileio/] [current/] [src/] [fd.cxx] - Rev 825

Go to most recent revision | Compare with Previous | Blame | View Log

//==========================================================================
//
//      fd.cxx
//
//      Fileio file descriptor implementation
//
//==========================================================================
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
// -------------------------------------------                              
// This file is part of eCos, the Embedded Configurable Operating System.   
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under    
// the terms of the GNU General Public License as published by the Free     
// Software Foundation; either version 2 or (at your option) any later      
// version.                                                                 
//
// eCos is distributed in the hope that it will be useful, but WITHOUT      
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
// for more details.                                                        
//
// You should have received a copy of the GNU General Public License        
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
//
// As a special exception, if other files instantiate templates or use      
// macros or inline functions from this file, or you compile this file      
// and link it with other works to produce a work based on this file,       
// this file does not by itself cause the resulting work to be covered by   
// the GNU General Public License. However the source code for this file    
// must still be made available in accordance with section (3) of the GNU   
// General Public License v2.                                               
//
// This exception does not invalidate any other reasons why a work based    
// on this file might be covered by the GNU General Public License.         
// -------------------------------------------                              
// ####ECOSGPLCOPYRIGHTEND####                                              
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):           nickg
// Contributors:        nickg
// Date:                2000-05-25
// Purpose:             Fileio file descriptor implementation
// Description:         This file contains the implementation of the file
//                      descriptor functions.
//              
//              
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/io_fileio.h>
 
#ifdef CYGPKG_KERNEL
#include <pkgconf/kernel.h>
#include <cyg/kernel/ktypes.h>         // base kernel types
#endif
#include <cyg/infra/cyg_trac.h>        // tracing macros
#include <cyg/infra/cyg_ass.h>         // assertion macros
 
#include "fio.h"                       // Private header
 
//-----------------------------------------------------------------------------
// File data structures
 
#ifdef CYGPKG_KERNEL
// Mutex for controlling access to file desriptor arrays
Cyg_Mutex fdlock CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
 
// Array of per-file mutexes
static Cyg_Mutex file_lock[CYGNUM_FILEIO_NFILE] \
    CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
#endif // ifdef CYGPKG_KERNEL
 
// Array of open file objects
static cyg_file file[CYGNUM_FILEIO_NFILE];
 
// Descriptor array
static cyg_file *desc[CYGNUM_FILEIO_NFD];
 
#define FD_ALLOCATED ((cyg_file *)1)
 
//==========================================================================
// Initialization
 
__externC void cyg_fd_init()
{
    int i;
 
    for( i = 0; i < CYGNUM_FILEIO_NFILE; i++ )
        file[i].f_flag = 0;
 
    for( i = 0; i < CYGNUM_FILEIO_NFD; i++ )
        desc[i] = NULL;
}
 
//==========================================================================
// File object allocation 
 
//--------------------------------------------------------------------------
// Locate and allocate a free file object.
 
__externC cyg_file *cyg_file_alloc()
{
    int i;
    cyg_file *fp = NULL;
 
    FILEIO_MUTEX_LOCK(fdlock);
 
    for( i = 0; i < CYGNUM_FILEIO_NFILE; i++ )
    {
        if( (file[i].f_flag & CYG_FALLOC) == 0 )
        {
            fp = &file[i];
            fp->f_flag = CYG_FALLOC;
            fp->f_ucount = 0;
            break;
        }
    }
 
    FILEIO_MUTEX_UNLOCK(fdlock);
 
    return fp;
}
 
//--------------------------------------------------------------------------
// Free a file object. This is a straightforward freeing, usually used
// during error recovery. File objects are normally freed as a side
// effect of cyg_fd_assign() or cyg_fd_free().
 
__externC void cyg_file_free(cyg_file * fp)
{
    FILEIO_MUTEX_LOCK(fdlock);
 
    fp->f_flag = 0;
 
    FILEIO_MUTEX_UNLOCK(fdlock);
}
 
//==========================================================================
// Internal routines for handling descriptor deallocation
// These must all be called with the fdlock already locked.
 
//--------------------------------------------------------------------------
// 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 )
{
    int error = 0;
    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);        
 
        fp->f_flag = 0;
    }
 
    return error;
}
 
//--------------------------------------------------------------------------
// Clear out a descriptor. If this is the last reference to the file
// object, then that will be closed and deallocated.
 
static int fd_close( int fd )
{
    int error = 0;
    cyg_file *fp;
 
    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)
    {
        // The descriptor is occupied, decrement its usecount and
        // close the file if it goes zero.
 
        error = fp_ucount_dec( fp );
    }
 
    return error;
}
 
 
//==========================================================================
// File descriptor allocation
 
//--------------------------------------------------------------------------
// Allocate a file descriptor. The allocated descriptor is set to the value
// FD_ALLOCATED to prevent it being reallocated by another thread.
 
__externC int cyg_fd_alloc(int low)
{
    int fd;
 
    CYG_ASSERT(((0 <= low) && (low<CYGNUM_FILEIO_NFD)),"fd out of range");
 
    FILEIO_MUTEX_LOCK(fdlock);
 
    for( fd = low; fd < CYGNUM_FILEIO_NFD; fd++ )
    {
        if( desc[fd] == NULL )
        {
            desc[fd] = FD_ALLOCATED;
            FILEIO_MUTEX_UNLOCK(fdlock);
            return fd;
        }
    }
 
    FILEIO_MUTEX_UNLOCK(fdlock);
 
    return -1;
}
 
//--------------------------------------------------------------------------
// Assign a file object to a descriptor. If the descriptor is already
// occupied, the occupying files usecount is decrement and it may be
// closed.
 
__externC void cyg_fd_assign(int fd, cyg_file *fp)
{
 
    CYG_ASSERT(((0 <= fd) && (fd<CYGNUM_FILEIO_NFD)),"fd out of range");
 
    FILEIO_MUTEX_LOCK(fdlock);
 
    fd_close( fd );
 
    fp->f_ucount++;
    desc[fd] = fp;
 
    FILEIO_MUTEX_UNLOCK(fdlock);    
}
 
//--------------------------------------------------------------------------
// Free a descriptor. Any occupying files usecount is decremented and
// it may be closed.
 
__externC int cyg_fd_free(int fd)
{
    int error;
 
    CYG_ASSERT(((0 <= fd) && (fd<CYGNUM_FILEIO_NFD)),"fd out of range");
 
    FILEIO_MUTEX_LOCK(fdlock);
 
    error = fd_close( fd );
 
    desc[fd] = NULL;
 
    FILEIO_MUTEX_UNLOCK(fdlock);
 
    return error;
}
 
//==========================================================================
// Descriptor to file object mapping
 
 
//--------------------------------------------------------------------------
// Map a descriptor to a file object. This is just a straightforward index
// into the descriptor array complicated by the need to lock the mutex and
// increment the usecount.
 
__externC cyg_file *cyg_fp_get( int fd )
{
    CYG_ASSERT(((0 <= fd) && (fd<CYGNUM_FILEIO_NFD)),"fd out of range");
 
    FILEIO_MUTEX_LOCK(fdlock);
 
    cyg_file *fp = desc[fd];
 
    if( fp != FD_ALLOCATED && fp != NULL)
    {
        // Increment use count while we work on this file
 
        fp->f_ucount++;
    }
    else fp = NULL;
 
    FILEIO_MUTEX_UNLOCK(fdlock);
 
    return fp;
}
 
//--------------------------------------------------------------------------
// Free the usecount reference we acquired in cyg_fp_get(). If the usecount
// is zeroed, the file will be closed.
 
__externC void cyg_fp_free( cyg_file *fp )
{
    FILEIO_MUTEX_LOCK(fdlock);
 
    fp_ucount_dec( fp );
 
    FILEIO_MUTEX_UNLOCK(fdlock);    
}
 
//==========================================================================
// File locking protocol
 
void cyg_file_lock( cyg_file *fp , cyg_uint32 syncmode )
{
    cyg_fs_lock( fp->f_mte, syncmode>>CYG_SYNCMODE_IO_SHIFT);
 
    if( syncmode & CYG_SYNCMODE_IO_FILE )
    {
        fp->f_flag |= CYG_FLOCKED;
        FILEIO_MUTEX_LOCK(file_lock[fp-&file[0]]);
    }
}
 
void cyg_file_unlock( cyg_file *fp, cyg_uint32 syncmode )
{
    cyg_fs_unlock( fp->f_mte, syncmode>>CYG_SYNCMODE_IO_SHIFT);
 
    if( syncmode & CYG_SYNCMODE_IO_FILE )
    {
        fp->f_flag &= ~CYG_FLOCKED;
        FILEIO_MUTEX_UNLOCK(file_lock[fp-&file[0]]);
    }
}
 
 
//==========================================================================
// POSIX API routines
 
//--------------------------------------------------------------------------
// dup() - duplicate an FD into a random descriptor
 
__externC int dup( int fd )
{
    cyg_file *fp = cyg_fp_get( fd );
 
    if( fp == NULL )
    {
        errno = EBADF;
        return -1;
    }
 
    int fd2 = cyg_fd_alloc(0);
 
    if( fd2 == -1 )
    {
        errno = EMFILE;
        return -1;
    }
 
    cyg_fd_assign( fd2, fp );
 
    cyg_fp_free(fp);
 
    return fd2;
}
 
//--------------------------------------------------------------------------
// dup2() - duplicate an FD into a chosen descriptor
 
__externC int dup2( int fd, int fd2 )
{
    if( fd2 == fd ) return fd2;
 
    if( fd2 < 0 || fd2 >= OPEN_MAX )
    {
        errno = EBADF;
        return -1;
    }
 
    cyg_file *fp = cyg_fp_get( fd );
 
    if( fp == NULL )
    {
        errno = EBADF;
        return -1;
    }
 
    cyg_fd_assign( fd2, fp );
 
    cyg_fp_free(fp);
 
    return fd2;
}
 
// -------------------------------------------------------------------------
// EOF fd.cxx
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.