/******************************************************************************* Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. This file is part of Sortix. Sortix 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 3 of the License, or (at your option) any later version. Sortix 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 Sortix. If not, see . dtable.cpp Table of file descriptors. *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include namespace Sortix { DescriptorTable::DescriptorTable() { dtablelock = KTHREAD_MUTEX_INITIALIZER; entries = NULL; numentries = 0; } DescriptorTable::~DescriptorTable() { Reset(); } bool DescriptorTable::IsGoodEntry(int i) { bool ret = 0 <= i && i < numentries && entries[i].desc; return ret; } Ref DescriptorTable::Fork() { ScopedLock lock(&dtablelock); Ref ret(new DescriptorTable); if ( !ret ) { return Ref(NULL); } ret->entries = new dtableent_t[numentries]; if ( !ret->entries ) { return Ref(NULL); } for ( ret->numentries = 0; ret->numentries < numentries; ret->numentries++ ) { int i = ret->numentries; if ( entries[i].desc && !(entries[i].flags & FD_CLOFORK) ) ret->entries[i] = entries[i]; else /* Already set to NULL in dtableent_t::desc constructor. */{} } return ret; } Ref DescriptorTable::Get(int index) { ScopedLock lock(&dtablelock); if ( !IsGoodEntry(index) ) { errno = EBADF; return Ref(NULL); } return entries[index].desc; } bool DescriptorTable::Enlargen(int atleast) { if ( numentries == INT_MAX ) { errno = EOVERFLOW; return -1; } int newnumentries = INT_MAX - numentries < numentries ? INT_MAX : numentries ? 2 * numentries : 8; if ( newnumentries < atleast ) newnumentries = atleast; dtableent_t* newentries = new dtableent_t[newnumentries]; if ( !newentries ) return false; for ( int i = 0; i < numentries; i++ ) newentries[i].desc = entries[i].desc, newentries[i].flags = entries[i].flags; for ( int i = numentries; i < newnumentries; i++ ) /* newentries[i].desc is set in dtableent_t::desc constructor */ newentries[i].flags = 0; delete[] entries; entries = newentries; numentries = newnumentries; return true; } int DescriptorTable::Allocate(Ref desc, int flags) { if ( flags & ~__FD_ALLOWED_FLAGS ) return errno = EINVAL, -1; ScopedLock lock(&dtablelock); for ( int i = 0; i < numentries; i++ ) if ( !entries[i].desc ) { entries[i].desc = desc; entries[i].flags = flags; return i; } int oldnumentries = numentries; if ( !Enlargen(0) ) return -1; int i = oldnumentries++; entries[i].desc = desc; entries[i].flags = flags; return i; } int DescriptorTable::Copy(int from, int to) { ScopedLock lock(&dtablelock); if ( from < 0 || to < 0 ) return errno = EINVAL, -1; if ( !(from < numentries) ) return errno = EBADF, -1; if ( !entries[from].desc ) return errno = EBADF, -1; while ( !(to < numentries) ) if ( !Enlargen(to+1) ) return -1; if ( entries[to].desc != entries[from].desc ) { if ( entries[to].desc ) /* TODO: Should this be synced or otherwise properly closed? */{} entries[to].desc = entries[from].desc; entries[to].flags = entries[from].flags; } return to; } Ref DescriptorTable::FreeKeep(int index) { ScopedLock lock(&dtablelock); if ( !IsGoodEntry(index) ) { errno = EBADF; return Ref(NULL); } Ref ret = entries[index].desc; entries[index].desc.Reset(); return ret; } void DescriptorTable::Free(int index) { FreeKeep(index); } void DescriptorTable::OnExecute() { ScopedLock lock(&dtablelock); for ( int i = 0; i < numentries; i++ ) { if ( !entries[i].desc ) continue; if ( !(entries[i].flags & FD_CLOEXEC) ) continue; entries[i].desc.Reset(); } } void DescriptorTable::Reset() { ScopedLock lock(&dtablelock); numentries = 0; delete[] entries; entries = NULL; } bool DescriptorTable::SetFlags(int index, int flags) { if ( flags & ~__FD_ALLOWED_FLAGS ) return errno = EINVAL, -1; ScopedLock lock(&dtablelock); if ( !IsGoodEntry(index) ) { errno = EBADF; return false; } entries[index].flags = flags; return true; } int DescriptorTable::GetFlags(int index) { ScopedLock lock(&dtablelock); if ( !IsGoodEntry(index) ) { errno = EBADF; return -1; } return entries[index].flags; } } // namespace Sortix