//-< SHMEM.H >-------------------------------------------------------*--------* // SHMEM Version 1.0 (c) 1998 GARRET * ? * // (Shared Memory Manager) * /\| * // * / \ * // Created: 28-Mar-98 K.A. Knizhnik * / [] \ * // Last update: 12-Apr-98 K.A. Knizhnik * GARRET * //-------------------------------------------------------------------*--------* // Shered Memory interface //-------------------------------------------------------------------*--------* #ifndef __SHMEM_H__ #define __SHMEM_H__ #include #include #include #ifdef _WIN32 #include #else #include "posixsem.h" #define INFINITE (~0U) #endif #ifdef USE_BASED_POINTERS extern void* shared_memory_base_pointer; #define REF(type) type __based(shared_memory_base_pointer)* #endif class shared_memory { public: enum lck_t { lck_shared, lck_exclusive }; enum open_mode { read_only, read_write }; class lock_descriptor { friend class shared_memory; public: const lck_t mode; lock_descriptor(lck_t lck) : mode(lck) {} protected: lock_descriptor* next; unsigned owner; }; // Status returned by shared_memory methods are either connstants // specified in the following enum or system error returned by GetLastError enum status { ok = 0, timeout_expired = -1, }; // // Find storage containing specified object // static shared_memory* find_storage(void* obj); // // Lock stotorage either in shared either in exclusive mode. // Several processes can lock storage in shared mode, while only // one in exclusive. Parameter "msec" specifies timeout for // waiting until lock will be granted. // status lock(lock_descriptor& lck, unsigned msec = INFINITE); status unlock(lock_descriptor& lck); // alloc() function returns NULL if there are not enough free memory void* allocate(size_t size, bool initialize_by_zero = true); void free(void* ptr); // Find storaghe containing specified object and free it static void deallocate(void* obj) { shared_memory* shmem = find_storage(obj); assert(shmem != NULL); shmem->free(obj); } status open(const char* file_name, const char* shared_name, size_t max_size, open_mode mode = read_write, void* desired_address = NULL); status flush(); void close(); char* get_error_text(status code, char* buf, size_t buf_size) const; void* get_root_object() const { return pHdr->root_object; } void set_root_object(void* root) { pHdr->root_object = root; } void check_heap() const; shared_memory(); protected: shared_memory* next; static shared_memory* chain; // L1-list of opened shared memory section struct allocation_block { // Offsets to next and previous object. If objects is not free // then these offsets are negative, otherwise positive. int backward; int forward; }; struct free_block : public allocation_block { #ifdef USE_BASED_POINTERS REF(free_block) next; REF(free_block) prev; #else free_block* next; free_block* prev; #endif void link_after(free_block* after) { (next = after->next)->prev = this; (prev = after)->next = this; } void unlink() { prev->next = next; next->prev = prev; } }; struct monitor { // Fields used for syncronization of access to shared memory long n_readers; long n_writers; long n_waiters; #ifdef _WIN32 long cs; #else msem_data cs; #endif long n_sessions; size_t max_file_size; void* base_address; }; struct header { void* base_address; #ifdef USE_BASED_POINTERS REF(void) root_object; REF(free_block) free_list_pos; #else void* root_object; free_block* free_list_pos; #endif free_block free_list; size_t size; int barrier; }; header* pHdr; monitor* pMonitor; #ifdef _WIN32 HANDLE hFile; HANDLE hCS; HANDLE hEvent; HANDLE hSemaphore; HANDLE hMutex; HANDLE hMap; HANDLE hMonitor; #else int fd; int sem; int shmid; int monid; sem_t mutex; msem_t cs; bool wait_resource(status&, lck_t, unsigned self, unsigned msec); #endif open_mode mode; lock_descriptor* shared_lock_chain; int n_nested_exclusive_locks; unsigned owner; // thread owner of exclusive lock bool enter_critical_section(status&); bool leave_critical_section(status&); }; // // Convinient locking mechanism, based on C++ local objects // class exclusive_lock : shared_memory::lock_descriptor { protected: shared_memory& shmem; public: exclusive_lock(shared_memory& shm) : shared_memory::lock_descriptor(shared_memory::lck_exclusive), shmem(shm) { shared_memory::status rc = shmem.lock(*this); assert(rc == shared_memory::ok); } ~exclusive_lock() { shared_memory::status rc = shmem.unlock(*this); assert(rc == shared_memory::ok); } }; class shared_lock : shared_memory::lock_descriptor { protected: shared_memory& shmem; public: shared_lock(shared_memory& shm) : shared_memory::lock_descriptor(shared_memory::lck_shared), shmem(shm) { shared_memory::status rc = shmem.lock(*this); assert(rc == shared_memory::ok); } ~shared_lock() { shared_memory::status rc = shmem.unlock(*this); assert(rc == shared_memory::ok); } }; // // System independent indetrface for synchronization primitives // class semaphore { // classical sempahore public: bool wait(unsigned msec = INFINITE); void signal(unsigned inc = 1); bool open(char const* name, unsigned init_value = 0); void close(); private: #ifdef _WIN32 HANDLE s; #else sem_t s; #endif }; class event { // event with manual reset public: bool wait(unsigned msec = INFINITE); void signal(); void reset(); bool open(char const* name, bool signaled = false); void close(); private: #ifdef _WIN32 HANDLE e; #else sem_t e; #endif }; #endif