// Copyright (C) 2010, Gabriel Dos Reis. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // - Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // - Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in // the documentation and/or other materials provided with the // distribution. // // - Neither the name of The Numerical Algorithms Group Ltd. nor the // names of its contributors may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER // OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --%: Gabriel Dos Reis. #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #include #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_MMAN_H # include #endif #ifdef OPENAXIOM_MS_WINDOWS_HOST # include #endif #include #include #include #include // for placement new. #include namespace OpenAxiom { // ---------------- // -- SystemError -- // ---------------- SystemError::SystemError(std::string s) : text(s) { } SystemError::~SystemError() { } const std::string& SystemError::message() const { return text; } void filesystem_error(std::string s) { throw SystemError(s); } namespace Memory { // Return storage page allocation unit in byte count. size_t page_size() { #if defined(OPENAXIOM_MS_WINDOWS_HOST) SYSTEM_INFO si = { }; GetSystemInfo(&si); return si.dwPageSize; #elif defined(HAVE_UNISTD_H) return sysconf(_SC_PAGESIZE); #else // Well, we have to return a number. return 4096; #endif } // Subroutine of os_acquire_raw_memory. Attempt to acquire // storage from the host OS. Return null on failure. static inline Pointer os_allocate_read_write_raw_memory(size_t nbytes) { #if defined(OPENAXIOM_MS_WINDOWS_HOST) return VirtualAlloc(Pointer(), nbytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); #elif defined(HAVE_SYS_MMAN_H) Pointer p = mmap(Pointer(), nbytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | OPENAXIOM_MM_ANONYMOUS_MAP_FLAG, -1, 0); return p == MAP_FAILED ? Pointer() : p; #else return malloc(byte_count); #endif } Pointer os_acquire_raw_memory(size_t nbytes) { Pointer p = os_allocate_read_write_raw_memory(nbytes); if (p == 0) throw SystemError("cannot acquire more memory"); return memset(p, nbytes, 0); } void os_release_raw_memory(Pointer p, size_t n) { #if defined(OPENAXIOM_MS_WINDOWS_HOST) VirtualFree(p, 0, MEM_RELEASE); #elif defined(HAVE_SYS_MMAN_H) munmap(p, n); #else free(p); #endif } // ------------- // -- Storage -- // ------------- Storage* Storage::acquire(size_t alignment, size_t byte_count) { // Adjust for overhead, and page boundary. byte_count = round_up(byte_count + sizeof(Storage), page_size()); Storage* mem = new(os_acquire_raw_memory(byte_count)) Storage; mem->limit_top = mem->base() + round_up(sizeof(Storage), alignment); mem->limit_bot = mem->base() + byte_count; mem->free = mem->limit_top; return mem; } void Storage::release(Storage* store) { os_release_raw_memory(store, store->extent()); } bool Storage::align_to(size_t alignment) { if (alignment == 0) // protect against nuts return true; if (alignment == 1) // no preferred alignment at all return true; Byte* b = base(); const size_t offset = round_up(free - b, alignment); if (offset < size_t(limit_bot - b)) { free = b + offset; return true; } return false; // not enough room left } // ----------------- // -- FileMapping -- // ----------------- FileMapping::FileMapping(std::string path) : start(), extent() { #if defined(OPENAXIOM_MS_WINDOWS_HOST) HANDLE file = CreateFile(path.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (file == INVALID_HANDLE_VALUE) filesystem_error("could not access file " + path); HANDLE mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, 0, 0); if (mapping == 0) filesystem_error("could not map file " + path); start = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); extent = GetFileSize(file, 0); CloseHandle(mapping); CloseHandle(file); #elif defined(HAVE_SYS_STAT_H) && defined(HAVE_SYS_MMAN_H) && defined(HAVE_FCNTL_H) struct stat s; errno = 0; if (stat(path.c_str(), &s) < 0) filesystem_error("could not access file " + path); else if (!S_ISREG(s.st_mode)) filesystem_error(path + " is not a regular file"); int fd = open(path.c_str(), O_RDONLY); if (fd < 0) filesystem_error("could not open " + path); start = mmap(Pointer(), s.st_size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); if (start == MAP_FAILED) filesystem_error("could not map file " + path); extent = s.st_size; #else # error "Don't know how to map a file on this platform" #endif // OPENAXIOM_MS_WINDOWS_HOST } FileMapping::~FileMapping() { #if defined(OPENAXIOM_MS_WINDOWS_HOST) UnmapViewOfFile(start); #elif defined(HAVE_SYS_MMAN_H) munmap(start, extent); #else # error "Don't know how to unmap a file on this platform" #endif } } }