// // memshm.cc // // Copyright (C) 1996 Limit Point Systems, Inc. // // Author: Curtis Janssen // Maintainer: LPS // // This file is part of the SC Toolkit. // // The SC Toolkit is free software; you can redistribute it and/or modify // it under the terms of the GNU Library General Public License as published by // the Free Software Foundation; either version 2, or (at your option) // any later version. // // The SC Toolkit 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 Library General Public License for more details. // // You should have received a copy of the GNU Library General Public License // along with the SC Toolkit; see the file COPYING.LIB. If not, write to // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. // // The U.S. Government is granted a limited license as per AL 91-7. // #ifndef _util_group_memshm_cc #define _util_group_memshm_cc #ifdef __GNUC__ #pragma implementation #endif #include #include #include #include #include using namespace std; using namespace sc; #ifndef SHMMAX // glibc 2.0.3 isn't defining SHMMAX so make set it here # ifdef __linux__ # define SHMMAX 0x1000000 # else # define SHMMAX INT_MAX # endif #endif #ifndef SHMMIN #define SHMMIN 1 #endif #ifndef SIMPLE_LOCK #define SIMPLE_LOCK 1 #endif #undef DEBUG static ClassDesc ShmMemoryGrp_cd( typeid(ShmMemoryGrp),"ShmMemoryGrp",1,"public MsgMemoryGrp", 0, create, 0); ShmMemoryGrp::ShmMemoryGrp(const Ref& msg): MsgMemoryGrp(msg) { update_ = 0; data_ = 0; memory_ = 0; pool_ = 0; rangelock_ = 0; nregion_ = 0; shmid_ = 0; attach_address_ = 0; } ShmMemoryGrp::ShmMemoryGrp(const Ref& keyval): MsgMemoryGrp(keyval) { update_ = 0; data_ = 0; memory_ = 0; pool_ = 0; rangelock_ = 0; nregion_ = 0; shmid_ = 0; attach_address_ = 0; } int ShmMemoryGrp::attach_memory(void *ataddress, int size) { int i; int fail = 0; int isize; int rsize = size; for (i=0; i0; i++,rsize-=isize) { isize = rsize; if (isize > SHMMAX) isize = SHMMAX; else if (isize < SHMMIN) isize = SHMMIN; if (debug_) { ExEnv::outn() << me() << ": "; ExEnv::outn() << "ShmMemoryGrp: attaching segment with " << isize << " bytes at address " << (void*)ataddress << " on node " << me() << endl; } attach_address_[i] = shmat(shmid_[i],(SHMTYPE)ataddress,0); if (debug_) { ExEnv::outn() << me() << ": "; ExEnv::outn() << "ShmMemoryGrp: got address " << (void*)attach_address_[i] << " on node " << me() << endl; } if (attach_address_[i] == 0 || attach_address_[i] == (void*) -1 || ataddress && attach_address_[i] != ataddress) { //ExEnv::outn() << "ShmMemoryGrp: shmat: problem attaching using address: " // << " " << (void*) ataddress // << ": got address: " // << (void*) attach_address_[i] // << " on node " << me() // << endl; fail = 1; } ataddress = (void*)((char*)(attach_address_[i]) + isize); } memory_ = (void*) attach_address_[0]; if (fail) detach_memory(); return fail; } void ShmMemoryGrp::detach_memory() { int i; for (i=0; i0; i++,rsize-=isize) { isize = rsize; if (isize > SHMMAX) isize = SHMMAX; else if (isize < SHMMIN) isize = SHMMIN; if (debug_) { ExEnv::outn() << me() << ": "; ExEnv::outn() << "ShmMemoryGrp: getting segment with " << isize << " bytes" << endl; } shmid_[i] = shmget(IPC_PRIVATE, isize, IPC_CREAT | SHM_R | SHM_W); if (shmid_[i] == -1) { ExEnv::outn() << me() << ": "; ExEnv::outn() << "ShmMemoryGrp: shmget failed for " << isize << " bytes: " << strerror(errno) << endl; abort(); } } } if (me() == 0) { lock_.initialize(); lock_ = 1; char * stringrep = lock_.stringrep(); int length = strlen(stringrep) + 1; msg_->bcast(&length, 1); msg_->bcast(stringrep, length); #ifdef DEBUG ExEnv::outn() << scprintf("%d: sent initialize string of \"%s\" (%d)\n", me(), stringrep, length); ExEnv::outn().flush(); #endif // DEBUG delete[] stringrep; for (i=0; ibcast(&length, 1); msg_->bcast(stringrep, length); #ifdef DEBUG ExEnv::outn() << scprintf("%d: sent initialize string of \"%s\" (%d) for %d\n", me(), stringrep, length, i); ExEnv::outn().flush(); #endif // DEBUG delete[] stringrep; } } else { int length; msg_->bcast(&length, 1); char * stringrep = new char[length]; msg_->bcast(stringrep, length); #ifdef DEBUG ExEnv::outn() << scprintf("%d: got initialize string of \"%s\" (%d)\n", me(), stringrep, length); ExEnv::outn().flush(); #endif // DEBUG lock_.initialize(stringrep); delete[] stringrep; for (i=0; ibcast(&length, 1); stringrep = new char[length]; msg_->bcast(stringrep, length); #ifdef DEBUG ExEnv::outn() << scprintf("%d: got initialize string of \"%s\" (%d) for %d\n", me(), stringrep, length, i); ExEnv::outn().flush(); #endif // DEBUG update_[i].initialize(stringrep); delete[] stringrep; } } // get an initial starting address on node 0 int ntry = 20; int itry; void *address; if (me() == 0) { address = 0; itry = 0; while (attach_memory(address,size) && itry < ntry) { if (address == 0) address = memory_; else address = (void*) &((char*)address)[0x1000000]; itry++; } if (itry == ntry) { ExEnv::errn() << "ShmMemoryGrp: ntry exhausted on node 0" << endl; abort(); } // detach again, since we all try together below detach_memory(); } msg_->bcast(shmid_, nregion_); msg_->raw_bcast((void*)&memory_, sizeof(void*)); address = memory_; itry = 0; int fail; do { fail = attach_memory(address,size); msg_->max(fail); if (fail) { detach_memory(); } address = (void*) &((char*)address)[0x1000000]; itry++; } while(fail && itry < ntry); if (itry == ntry) { ExEnv::errn() << "ShmMemoryGrp: ntry exhausted on node " << me() << " on joint attach phase" << endl; abort(); } if (me() == 0) { // initialize the pool pool_ = new(memory_) Pool(poolallocation); rangelock_ = new(pool_->allocate(sizeof(RangeLock))) RangeLock(pool_); } msg_->raw_bcast((void*)&pool_, sizeof(void*)); msg_->raw_bcast((void*)&rangelock_, sizeof(void*)); if (debug_) { ExEnv::outn() << scprintf("%d: memory_ = 0x%x shmid_[0] = %d\n", me(), memory_, shmid_[0]); } data_ = (void *) &((char*)memory_)[poolallocation]; } void * ShmMemoryGrp::localdata() { return &((char*)data_)[distsize_to_size(localoffset())]; } void ShmMemoryGrp::cleanup() { if (memory_) { for (int i=0; isync(); if (me() == 0) { for (int i=0; inreference() = %d\n", msg_->nreference()); ExEnv::outn().flush(); #endif // DEBUG msg_ = 0; } void * ShmMemoryGrp::obtain_readwrite(distsize_t offset, int size) { if (offset + size > totalsize()) { ExEnv::errn() << scprintf("ShmMemoryGrp::obtain_readwrite: arg out of range\n"); abort(); } #if SIMPLE_LOCK obtain_lock(); #else // SIMPLE_LOCK #ifdef DEBUG ExEnv::outn() << scprintf("%d: clear_release_count\n", me()); ExEnv::outn().flush(); #endif // DEBUG clear_release_count(); #ifdef DEBUG ExEnv::outn() << scprintf("%d: obtain_lock\n", me()); ExEnv::outn().flush(); #endif // DEBUG obtain_lock(); #ifdef DEBUG ExEnv::outn() << scprintf("%d: checkeq\n", me()); ExEnv::outn().flush(); #endif while (!rangelock_->checkeq(offset, offset + size, 0)) { #ifdef DEBUG ExEnv::outn() << scprintf("%d: range not zero -- waiting for release\n", me()); ExEnv::outn().flush(); #endif // DEBUG //rangelock_->print(); release_lock(); wait_for_release(); obtain_lock(); } rangelock_->decrement(offset, offset + size); #ifdef DEBUG ExEnv::outn() << scprintf("%d: after obtain write\n", me()); ExEnv::outn().flush(); //rangelock_->print(); #endif // DEBUG release_lock(); #endif // SIMPLE_LOCK return &((char*)data_)[distsize_to_size(offset)]; } void * ShmMemoryGrp::obtain_readonly(distsize_t offset, int size) { if (offset + size > totalsize()) { ExEnv::errn() << scprintf("ShmMemoryGrp::obtain_readonly: arg out of range\n"); abort(); } return &((char*)data_)[distsize_to_size(offset)]; } void * ShmMemoryGrp::obtain_writeonly(distsize_t offset, int size) { if (offset + size > totalsize()) { ExEnv::errn() << scprintf("ShmMemoryGrp::obtain_writeonly: arg out of range\n"); abort(); } return &((char*)data_)[distsize_to_size(offset)]; } void ShmMemoryGrp::release_readonly(void *data, distsize_t offset, int size) { } void ShmMemoryGrp::release_writeonly(void *data, distsize_t offset, int size) { } void ShmMemoryGrp::release_readwrite(void *data, distsize_t offset, int size) { #if SIMPLE_LOCK release_lock(); #else // SIMPLE_LOCK obtain_lock(); rangelock_->increment(offset, offset + size); note_release(); #ifdef DEBUG ExEnv::outn() << scprintf("%d: after release write\n", me()); //rangelock_->print(); ExEnv::outn().flush(); #endif // DEBUG release_lock(); #endif // SIMPLE_LOCK } void ShmMemoryGrp::obtain_lock() { #ifdef DEBUG ExEnv::outn() << scprintf("%d: lock val = %d\n", me(), lock_.val()); ExEnv::outn().flush(); #endif // DEBUG lock_--; #ifdef DEBUG ExEnv::outn() << scprintf("%d: lock decremented\n", me()); ExEnv::outn().flush(); #endif // DEBUG } void ShmMemoryGrp::release_lock() { lock_++; #ifdef DEBUG ExEnv::outn() << scprintf("%d: incremented lock\n", me()); ExEnv::outn().flush(); #endif // DEBUG } void ShmMemoryGrp::note_release() { for (int i=0; i