bool editable_events::load_events () { bool result; int original_count = m_sequence.events().count(); for ( event_list::const_iterator ei = m_sequence.events().begin(); ei != m_sequence.events().end(); ++ei ) { if (! add(DREF(ei))) break; } result = count() == original_count; #ifdef USE_VERIFY_AND_LINK /* not yet ready */ if (result && count() > 1) m_events.verify_and_link(); #endif return result; }
/* static */ SysStatus FRPA::Create(ObjectHandle &oh, uval processID, ObjectHandle file, uval len, uval fileToken, char *name, uval namelen, KernelPagingTransportRef kptref) { SysStatus rc; FRPARef frref; ProcessRef pref; FRPA *fr; // get process ref for calling file system rc = DREFGOBJ(TheProcessSetRef)->getRefFromPID(processID, (BaseProcessRef&)pref); tassertMsg(_SUCCESS(rc), "calling process can't go away??\n"); fr = new FRPA; tassertMsg( (fr!=NULL), "alloc should never fail\n"); rc = fr->init(file, len, fileToken, name, namelen, kptref); tassertMsg( _SUCCESS(rc), "woops\n"); frref = (FRPARef)CObjRootSingleRep::Create(fr); // call giveAccessInternal here to provide fileSystemAccess to // the file systems OH // note that we set the client data to 1 to mark this as the fr // oh so we know if the fs goes away rc = DREF(frref)->giveAccessInternal( oh, processID, MetaFR::fileSystemAccess|MetaObj::controlAccess|MetaObj::attach, MetaObj::none, 0, 1); if (_FAILURE(rc)) return rc; return 0; }
/* virtual */ SysStatus FCMDefault::ioCompleteInternal(PageDesc* pg, SysStatus rc, PageFaultNotification* skipFn, uval keepLock) { _ASSERT_HELD(lock); if (pg->freeAfterIO) { uval vaddr; pg->doingIO = PageDesc::CLEAR; // we are meant to get rid of this page tassert(!pg->mapped, err_printf("Freeing but mapped\n")); // indicate that we are given up ownership of pages // PageAllocatorKernPinned::clearFrameDesc(pg->paddr); // give back physical page vaddr = PageAllocatorKernPinned::realToVirt(pg->paddr); DREF(pmRef)->deallocPages(getRef(), vaddr, pg->len); // notify waiters, but retain lock notify(pg, rc, skipFn, 1); tassertWrn(pg->freeAfterIO,"Should not have freed page: %p %p\n", pg,pg->fn); // remove from page list pageList.remove(pg->fileOffset); lock.release(); checkEmpty(); return 2; // page has disappeared } else { // when either read or write completes // page is "clean" since it matches the disk DILMA_TRACE_PAGE_DIRTY(this,pg,-1); pg->dirty = PageDesc::CLEAR; pg->doingIO = PageDesc::CLEAR; notify(pg, rc, skipFn, keepLock); } return 0; }
/* virtual */ SysStatus MemTrans::giveAccessSetClientData(ObjectHandle &oh, ProcessID toProcID, AccessRights match, AccessRights nomatch, TypeID type) { SysStatus rc; ClientData *clientData = new ClientData(toProcID); rc = giveAccessInternal(oh, toProcID, match, nomatch, type, (uval)clientData); if (_FAILURE(rc)) { delete clientData; } // Remember the process binding BaseProcessRef pref; rc = DREFGOBJ(TheProcessSetRef)->getRefFromPID(toProcID,pref); _IF_FAILURE_RET_VERBOSE(rc); XHandle remote = oh.xhandle(); //Add ref count for xhandle incRefCount(); rc = DREF(pref)->addSMT(getRef(), remote, key); _IF_FAILURE_RET(rc); clientData->givenOH = oh; cdHash.add(toProcID, clientData); dprintf("%s: add xh: %lx -> %ld\n",__func__,oh.xhandle(),toProcID); return rc; }
/* virtual */ SysStatus XHandleTrans::free(XHandle xhandle) { XBaseObj *xBaseObj; ObjRef objRef; BaseProcessRef procRef; SysStatus rc; SysStatusProcessID processPID; // no lock is held, so these pointers can dissapear // out from under us. That's why we copy and test. // also, the xhandle may already be free, so all errors // just lead to returning tassertMsg(XHANDLE_IDX(xhandle) >= CObjGlobals::numReservedEntries, "Freeing global xhandle\n"); xBaseObj = &xhandleTable[XHANDLE_IDX(xhandle)]; objRef = xBaseObj->__iobj; processPID = xBaseObj->getOwnerProcessID(); #ifdef __NO_REGISTER_WITH_KERNEL_WRAPPER if (processPID != _KERNEL_PID) { // we know kernel will not go away, don't insert in process list, // since this ProcessWrapper becomes a hot spot in file systems rc = DREFGOBJ(TheProcessSetRef)-> getRefFromPID(xBaseObj->getOwnerProcessID(), procRef); if (_FAILURE(rc)) { tassert(!(xBaseObj->isValid()), err_printf("PID %ld invalid in valid Xobj\n", xBaseObj->getOwnerProcessID())); return 0; } if (!procRef) return 0; } #else rc = DREFGOBJ(TheProcessSetRef)-> getRefFromPID(xBaseObj->getOwnerProcessID(), procRef); if (_FAILURE(rc)) { tassert(!(xBaseObj->isValid()), err_printf("PID %ld invalid in valid Xobj\n", xBaseObj->getOwnerProcessID())); return 0; } if (!procRef) return 0; #endif if ((!objRef)) return 0; if ((rc=DREF(objRef)->publicLockExportedXObjectList())) return 0; #ifdef __NO_REGISTER_WITH_KERNEL_WRAPPER if (processPID != _KERNEL_PID) { if ((rc=DREF(procRef)->lockMatchedXObjectList())) { DREF(objRef)->publicUnlockExportedXObjectList(); return 0; } } #else if ((rc=DREF(procRef)->lockMatchedXObjectList())) { DREF(objRef)->publicUnlockExportedXObjectList(); return 0; } #endif //once we have the locks, the XObject state can't change out from //under us. if (xBaseObj->isValid()) { /* kill xobject so subsequent calls fail don't need a sync - * token circulates before xobj becomes unsafe for stale * references remove from process and object lists. Remove * holder from lists and reset __nummeth to prevent another * releaseAccess call (inflight) from trying to free this * again. */ xBaseObj->__nummeth = 0; #ifdef __NO_REGISTER_WITH_KERNEL_WRAPPER if (processPID != _KERNEL_PID) { DREF(procRef)->removeMatchedXObj(xhandle); } #else DREF(procRef)->removeMatchedXObj(xhandle); #endif DREF(objRef)->removeExportedXObj(xhandle); // release locks before callback #ifdef __NO_REGISTER_WITH_KERNEL_WRAPPER if (processPID != _KERNEL_PID) { DREF(procRef)->unlockMatchedXObjectList(); } #else DREF(procRef)->unlockMatchedXObjectList(); #endif DREF(objRef)->publicUnlockExportedXObjectList(); xBaseObj->setBeingFreed(0); DREF(objRef)->handleXObjFree(xhandle); XBaseObj *removed; // must to this after removes - same space is used for both do { removed = removedEntries; xBaseObj->setNextFree(removed); } while (!CompareAndStoreSynced((uval*)(&removedEntries), (uval)removed, (uval)xBaseObj)); numberRemoved++; // doesn't have to be exact, // so don't sync } else { // race - someone else freed the XObject // release locks using original values. #ifdef __NO_REGISTER_WITH_KERNEL_WRAPPER if (processPID != _KERNEL_PID) { DREF(procRef)->unlockMatchedXObjectList(); } #else DREF(procRef)->unlockMatchedXObjectList(); #endif DREF(objRef)->publicUnlockExportedXObjectList(); } if ((numberRemoved % XHANDLE_TABLE_GC_INTERVAL) == 0) processToken(); return 0; }
/* virtual */ SysStatusXHandle XHandleTrans::alloc(ObjRef oref, BaseProcessRef pref, AccessRights matched, AccessRights unmatched, COVTableEntry* vtbl, uval8 numMethods, uval clientData) { SysStatus rc = 0; XBaseObj *te; SysStatusProcessID matchPID; // lock the obj and process lists // we munch the static function to be a member function so to speak uval idx = CObjGlobals::GlobalXHandleIdx(oref); if (idx && (matched & MetaObj::globalHandle)) { te = &xhandleTable[idx]; } else do { /* * because these objects are managed with ReadCopyUpdate * its safe to do a non-blocking pop. If the top object * disappears, it cant re-appear will this thread completes */ while ((te = freeEntries)) { XBaseObj* next; next=te->getNextFree(); if (CompareAndStoreSynced( (uval*)(&freeEntries), (uval)te, (uval)next)) break; } if (te == 0) { // Free list is empty. See if any previous of frees can // be completed. processToken(); if (freeEntries == 0) { // Free list is still empty. Allocate a new chunk of // the table, guarded by oldEntries lock oldEntries.acquire(); // check after getting the lock to avoid duplicate extends if (FetchAndNop((uval*)&freeEntries) == 0) { XBaseObj *top, *bottom, *oldFree; uval const newLimit = xhandleTableLimit + XHANDLE_TABLE_INCREMENT; passertMsg(newLimit <= XHANDLE_TABLE_MAX, "Quasi-infinite xhandle table exhausted.\n"); InitXHandleRange(xhandleTable, xhandleTableLimit, newLimit, top, bottom); xhandleTableLimit = newLimit; rc = DREFGOBJ(TheDispatcherMgrRef)-> publishXHandleTable(xhandleTable, xhandleTableLimit); tassertMsg(_SUCCESS(rc),"publishXHandleTable failed.\n"); // must not make new entries available until limit is moved do { oldFree = freeEntries; bottom->setNextFree(oldFree); } while (!(CompareAndStoreSynced( (uval*)(&freeEntries), (uval)oldFree, (uval)top))); } oldEntries.release(); } } } while (te == 0); matchPID = DREF(pref)->getPID(); tassertMsg(_SUCCESS(matchPID), "bad process ref passed in alloc %lx\n",rc); if (_FAILURE(rc = DREF(oref)->publicLockExportedXObjectList())) goto exit1; #ifdef __NO_REGISTER_WITH_KERNEL_WRAPPER if (matchPID != _KERNEL_PID) { // we know kernel will not go away, don't insert in process list, // since this ProcessWrapper becomes a hot spot in file systems if (_FAILURE(rc = DREF(pref)->lockMatchedXObjectList())) goto exit2; } #else if (_FAILURE(rc = DREF(pref)->lockMatchedXObjectList())) goto exit2; #endif // populate the translation entry, make sure vtable is last // do not modify the seqNo which is incremented on free te->__iobj = oref; te->__matchPID = _SGETPID(matchPID); te->__mrights = matched | MetaObj::processOnly; te->__urights = unmatched; te->clientData = clientData; XHandle xhandle; xhandle = te->getXHandle(); // add to process and object lists - can't fail, lock is held #ifdef __NO_REGISTER_WITH_KERNEL_WRAPPER if (matchPID != _KERNEL_PID) { DREF(pref)->addMatchedXObj(xhandle); } #else DREF(pref)->addMatchedXObj(xhandle); #endif DREF(oref)->addExportedXObj(xhandle); // now stick in the vtable pointer XBaseObj::SetFTable(te, vtbl); // now sync and then make the xobject valid // N.B. nummeth is valid flag SyncBeforeRelease(); te->__nummeth = numMethods; tassertMsg(numMethods != 0, "numMethods is 0 for xhandle 0x%lx\n", xhandle); #ifdef __NO_REGISTER_WITH_KERNEL_WRAPPER if (matchPID != _KERNEL_PID) { DREF(pref)->unlockMatchedXObjectList(); } #else DREF(pref)->unlockMatchedXObjectList(); #endif DREF(oref)->publicUnlockExportedXObjectList(); return xhandle; exit2: DREF(oref)->publicUnlockExportedXObjectList(); exit1: // Return the entry we acquired to the removed list // We don't put it on the free list because we want ReadCopyUpdate // guarantees for nonblocking access to freelist. XBaseObj *removed; te->setBeingFreed(0); // make sure since its going // through removed cycle do { removed = removedEntries; te->setNextFree(removed); } while (!CompareAndStoreSynced((uval*)(&removedEntries), (uval)removed, (uval)te)); numberRemoved++; // doesn't have to be exact, // so don't sync return rc; }
/* virtual */ SysStatus FileLinuxFile::destroy() { SysStatus rc; FLFDEBUG("destroy"); AutoLock<StreamLockType> al(&streamLock); // locks now, unlocks on return //err_printf("Started destroy() ref %p xhandle %lx\n", // getRef(), (uval) stub.getOH().xhandle()); uval64 oldDestroyAck = FetchAndOr64(&destroyAckSync, 2); if (oldDestroyAck & 1) { uval interval = 2000; // do this in cycles, not time // FIXME: this is an ugly stolen code ... get from other place while ((destroyAckSync & 1) && interval < 20000000UL) { Scheduler::DelayUntil(interval, TimerEvent::relative); interval = interval*10; // back off to avoid livelock } tassertMsg((destroyAckSync & 1)==0, "waiting was not enough?!\n"); } { // remove all ObjRefs to this object SysStatus rc = closeExportedXObjectList(); // most likely cause is that another destroy is in progress // in which case we return success if (_FAILURE(rc)) return (_SCLSCD(rc) == 1) ? 0 : rc; } #ifndef ENABLE_SYNCSERVICE rc = locked_flush(); tassertMsg(_SUCCESS(rc), "?"); #endif delete buffer; #ifndef NDEBUG /* We assert that no locks are held here because the below * _releaseAccess() call is going to result in the locks being * irretrievably lost. Remove this assertion as soon as the lock * lossage is fixed. */ struct flock currLock; rc = getLock(currLock); if (rc == 0) { tassertWrn(currLock.l_type == F_UNLCK, "We are about to lose our advisory file locks\n"); } #endif rc = stub._releaseAccess(); tassertMsg(_SUCCESS(rc), "not dealing with this error\n"); if (callBackUseTypeRegistered == 1) { rc = DREF(callBackUseTypeObjRef)->destroy(); tassertMsg(_SUCCESS(rc), "destroy of callBackUseTypeObjRef failed\n"); } // FIXME: potentially leaking callBackLockObjRef destroyUnchecked(); return 0; }
/* virtual */ SysStatusProcessID RegionReplicated::getPID() { return DREF(COGLOBAL(proc))->getPID(); }
SysStatus RegionReplicated::RegionReplicatedRoot::initRegion( ProcessRef pRef, uval &vaddr, uval vaddr2, uval size, uval alignreq, FRRef frRef, uval writable, uval fOff, AccessMode::mode accessreq, uval useVaddr, RegionType::Type regionType) { SysStatus rc=0; PMRef pmRef; size = PAGE_ROUND_UP(size); tassertWrn(!useVaddr || (PAGE_ROUND_DOWN(vaddr)==vaddr), "creating an unaligned region, vaddr=%lx\n", vaddr); rc = DREF(pRef)->getPM(pmRef); if (!_SUCCESS(rc)) return rc; regionState = CREATING; /* * we record the actual permission of the FR. This is so that * if a debugger asks to write a readonly mapping, we can decide * if its legal. * Of course, we also use this to prevent an initial writable * mapping of a read only FR. */ writeAllowed = writable; rc = DREF(pRef)->getHATProcess(hat); tassert(_SUCCESS(rc), err_printf("process destroyed\n")); regionVaddr = vaddr; regionSize = size; proc = pRef; access = accessreq; alignment = alignreq; fileOffset = fOff; /* can make regions without an fcm - see redzone for example * we attach first so we can ask fcm if it uses shared segments */ if (frRef) { rc = DREF(frRef)->attachRegion(fcm, (RegionRef)getRef(), pmRef, accessreq); tassertWrn(_SUCCESS(rc), "attach failed\n"); if (_FAILURE(rc)) { fcm = 0; // clear our fcm field tassert(0,err_printf("attach failed\n")); // FIXME we going to have a problem if we just call destroy // because that will attempt to create a // rep to call the method on, but we are currently holding // a lock preventing reps from being created (*((RegionRef)getRef()))->destroy(); // destroy ourselves regionState = DESTROYING; return rc; } } else { fcm = NULL; } // If ok, attach the region to the process // attach newly contructed region to process if (useVaddr) { rc = DREF(pRef)->attachFixedRegion( regionVaddr, regionSize, (RegionRef)getRef(), regionType); } else if (vaddr2 == 0) { // alignment fix up for shared segments if(size >= SEGMENT_SIZE && alignment == 0 && !useVaddr && fcm && DREF(fcm)->sharedSegments()) { alignment = SEGMENT_SIZE; } rc = DREF(pRef)->attachDynamicRegion( regionVaddr, regionSize, (RegionRef)getRef(), regionType, alignment); // return address allocated by process vaddr = regionVaddr; } else { rc = DREF(pRef)->attachWithinRangeRegion( vaddr, vaddr2, regionSize, (RegionRef)getRef(), regionType, alignment); regionVaddr = vaddr; } if (!_SUCCESS(rc)) { // failed - delete it tassert(0,err_printf("Region constructor failed\n")); if (fcm != NULL) { DREF(fcm)->detachRegion((RegionRef)getRef()); fcm = NULL; } // FIXME we are going to have a problem if we just call destroy // unchecked because that will attempt to create a // rep to call the method on, but we are currently holding // a lock preventing reps from being created (*((RegionRef)getRef()))->destroyUnchecked(); // free ref regionState = DESTROYING; return rc; } // unmap any full segments so shared mappings can be used if ((SEGMENT_ROUND_DOWN(vaddr+size)>SEGMENT_ROUND_UP(vaddr)) && fcm && DREF(fcm)->sharedSegments()) { rc = DREF(hat)->unmapRange( SEGMENT_ROUND_UP(vaddr), SEGMENT_ROUND_DOWN(vaddr+size)- SEGMENT_ROUND_UP(vaddr), ppset); tassert(_SUCCESS(rc), err_printf("oops\n")); } regionState = NORMAL; return rc; }
SysStatusUval RegionReplicated::handleFaultInternal(AccessMode::pageFaultInfo pfinfo, uval vaddr, PageFaultNotification *pn, VPNum vp, uval fileOffset) { SysStatus rc; uval user; uval firstAccessOnPP; uval myvp = Scheduler::GetVP(); if (requests.enter() < 0) { //FIXME return correct error for can't map page //N.B. when enter fails, DO NOT leave() return _SERROR(1402, 0, EFAULT); } #if 0 err_printf("enter %lx %ld\n",vaddr, vp); if (vaddr == stopAddr) { breakpoint(); } #endif /* #if 0 */ rc = DREF(COGLOBAL(proc))->getUserMode(user); if (rc) goto leave; if ((vaddr < COGLOBAL(regionVaddr)) || (vaddr >= (COGLOBAL(regionVaddr) + COGLOBAL(regionSize))) || !AccessMode::verifyAccess(user, COGLOBAL(access), pfinfo)) { if ((vaddr < COGLOBAL(regionVaddr)) || (vaddr >= (COGLOBAL(regionVaddr) + COGLOBAL(regionSize)))) { rc = _SERROR(1403, 0, EFAULT); } else { rc = _SERROR(1404, 0, EACCES); } goto leave; } firstAccessOnPP = 0; // atomically set bit if not already set if (!(COGLOBAL(ppset)).isSet(myvp)) { (COGLOBAL(ppset)).atomicAddVP(myvp); firstAccessOnPP = 1; } vaddr = vaddr&(-PAGE_SIZE); // convert to page address rc = DREF(COGLOBAL(fcm))->mapPage(fileOffset, COGLOBAL(regionVaddr), COGLOBAL(regionSize), pfinfo, vaddr, COGLOBAL(access), COGLOBAL(hat), vp, getRef(), firstAccessOnPP, pn); tassert(_SUCCESS(rc), err_printf("Can't allocate a page frame in RegionReplicated\n")); //N.B. all exits must do a leave - even errors leave: requests.leave(); #if 0 err_printf("leave %lx %ld\n",vaddr, vp); #endif /* #if 0 */ return (rc); }
SysStatus ProcessVPList::detachDispatcher(CPUDomainAnnex *cda, DispatcherID dspid, HATRef hatRef) { SysStatus rc; VPInfo *vpInfo; ProcessAnnex *pa; uval64 ipcRetryIDs; tassertMsg(cda->getPP() == Scheduler::GetVP(), "CDA not on this pp.\n"); RDNum rd; VPNum vp; SysTypes::UNPACK_DSPID(dspid, rd, vp); if (requests.enter() < 0) { return _SERROR(2642, 0, ESRCH); // process being destroyed } rc = findProcessAnnex(rd, vp, vpInfo, pa); if (_FAILURE(rc)) { requests.leave(); return rc; } if (!pa->isAttached(cda)) { requests.leave(); return _SERROR(2643, 0, EINVAL); } vpInfo->lock.acquire(); disableHardwareInterrupts(); if (pa->reservedThread != NULL) { /* * FIXME: For now, don't try to detach a dispatcher that is currently * disabled. We have to do better in the long run. */ enableHardwareInterrupts(); rc = _SERROR(2312, 0, EAGAIN); goto CleanupAndReturn; } pa->detach(); exceptionLocal.ipcTargetTable.remove(pa); if (KernelTimer::TimerRequestTime(pa) != SysTime(-1)) { /* * PA has a timeout request registered. Rather than try to reproduce * it on the new processor, we simply generate a TIMER_EVENT soft * interrupt so that the dispatcher can sort things out for itself. */ (void) pa->dispatcher->interrupts.fetchAndSet(SoftIntr::TIMER_EVENT); } exceptionLocal.kernelTimer.remove(pa); ipcRetryIDs = IPCRetryManager::GetIPCRetryIDs(pa); if (ipcRetryIDs != 0) { /* * PA has IPCs waiting to be retried. Simply generate notifications * for all of them, to be delivered when the dispatcher runs. */ pa->dispatcher->ipcRetry |= ipcRetryIDs; (void) pa->dispatcher->interrupts. fetchAndSet(SoftIntr::IPC_RETRY_NOTIFY); } exceptionLocal.ipcRetryManager.remove(pa); enableHardwareInterrupts(); vpInfo->dspCounter--; if (vpInfo->dspCounter > 0) { rc = 0; goto CleanupAndReturn; } /* * This VP's last dispatcher has now been detached, so detach the VP. * Switch to the canonical kernel address space, in case we're currently * "borrowing" the address space we're about to unmap. */ ((HATKernel*)(DREFGOBJK(TheKernelHATRef)))->switchToKernelAddressSpace(); rc = DREF(hatRef)->detachVP(vp); tassertMsg(_SUCCESS(rc), "hat->detachVP() failed.\n"); vpInfo->pp = ProcessAnnex::NO_PHYS_PROC; // VP now ready for re-attachment rc = 0; CleanupAndReturn: vpInfo->lock.release(); requests.leave(); return rc; }
SysStatus ProcessVPList::createDispatcher(CPUDomainAnnex *cda, DispatcherID dspid, EntryPointDesc entry, uval dispatcherAddr, uval initMsgLength, char *initMsg, ProcessRef procRef, HATRef hatRef) { SysStatus rc; VPInfo *vpInfo; uval newLimit, size; DspTable *newTable; ProcessAnnex *pa; SegmentTable *segTable; Dispatcher *dsp, *dspUser; RegionRef dspRegRef; FCMRef dspFCMRef; uval dspOffset, dspAddrKern; tassertMsg(cda->getPP() == Scheduler::GetVP(), "CDA not on this pp.\n"); RDNum rd; VPNum vp; SysTypes::UNPACK_DSPID(dspid, rd, vp); if (vp >= Scheduler::VPLimit) { return _SERROR(1752, 0, EINVAL); } if (rd >= Scheduler::RDLimit) { return _SERROR(1751, 0, EINVAL); } if (PAGE_ROUND_DOWN(dispatcherAddr) != dispatcherAddr) { return _SERROR(1327, 0, EINVAL); } if (requests.enter() < 0) { return _SERROR(1328, 0, ESRCH); // process being destroyed } if ((vp < vpLimit) && (dspTable->vpInfo[vp] != NULL)) { vpInfo = dspTable->vpInfo[vp]; } else { // We don't have a VPInfo structure for this vp. Create one, guarded // by stop()'ing requests. RequestCountWithStop doesn't support an // upgrade operation, so we have to "leave" before we can "stop". requests.leave(); if (requests.stop() < 0) { return _SERROR(2640, 0, ESRCH); // process being destroyed } if (vp >= vpLimit) { // We have to increase the size of the table. We make the first // increment larger than subsequent ones to lessen ramp-up costs. newLimit = (vpLimit == 1) ? 16 : (vpLimit * 2); // Make sure the newLimit is large enough to include vp. We won't // blow up because we know that vp < Scheduler::VPLimit. while (vp >= newLimit) { newLimit *= 2; } // Allocate a new table. DspTable includes space for one VPInfo // pointer, hence the "newLimit - 1" in the following calculation. size = sizeof(DspTable) + ((newLimit - 1) * sizeof(VPInfo *)); newTable = (DspTable *) AllocGlobalPadded::alloc(size); tassertMsg(newTable != NULL, "DspTable allocation failed.\n"); // Copy content of the old table to the new, and initialize the // rest of the new table. for (uval i = 0; i < vpLimit; i++) { newTable->vpInfo[i] = dspTable->vpInfo[i]; } for (uval i = vpLimit; i < newLimit; i++) { newTable->vpInfo[i] = NULL; } // Free the old table, unless it is the initial (pre-allocated) // table. if (vpLimit > 1) { size = sizeof(DspTable) + ((vpLimit - 1) * sizeof(VPInfo *)); AllocGlobalPadded::free(dspTable, size); } // Install the new table. dspTable = newTable; vpLimit = newLimit; } // We have to check vpInfo[vp] again now that requests are stop'd. vpInfo = dspTable->vpInfo[vp]; if (vpInfo == NULL) { if (vp == 0) { // Space for the first VPInfo structure is pre-allocated. vpInfo = &vpInfo0; } else { vpInfo = new VPInfo; tassertMsg(vpInfo != NULL, "VPInfo allocation failed.\n"); } vpInfo->init(cda->getPP()); dspTable->vpInfo[vp] = vpInfo; vpCounter++; if (!KernelInfo::ControlFlagIsSet(KernelInfo::RUN_SILENT)) { err_printf("Mapping program %s, pid 0x%lx, vp %ld to pp %ld.\n", name, processID, vp, vpInfo->pp); } } // Restart and then re-enter the request counter. requests.restart(); if (requests.enter() < 0) { return _SERROR(2641, 0, ESRCH); // process being destroyed } } /* * At this point the requests counter has been enter'd and vpInfo points * to a valid VPInfo structure for this vp. All further processing is * done under the vp lock. */ vpInfo->lock.acquire(); if (vpInfo->pp != cda->getPP()) { // VP is not on this physical processor. rc = _SERROR(1750, 0, EINVAL); goto CleanupAndReturn; } if (vpInfo->dspInfo[rd].pa != NULL) { // Dispatcher already exists. rc = _SERROR(1329, 0, EEXIST); goto CleanupAndReturn; } dspUser = (Dispatcher *) dispatcherAddr; if (isKern) { dspFCMRef = NULL; dspOffset = 0; dsp = dspUser; // Set a bogus interrupt bit to make the dispatcher runnable. (void) dsp->interrupts.fetchAndSet(SoftIntr::PREEMPT); } else { rc = DREF(procRef)->vaddrToRegion(dispatcherAddr, dspRegRef); if (_FAILURE(rc)) goto CleanupAndReturn; rc = DREF(dspRegRef)->vaddrToFCM(vp, dispatcherAddr, 0, dspFCMRef, dspOffset); if (_FAILURE(rc)) goto CleanupAndReturn; rc = DREF(dspFCMRef)->addReference(); if (_FAILURE(rc)) goto CleanupAndReturn; rc = archAllocDispatcherPage(dispatcherAddr, dspAddrKern); tassertMsg(_SUCCESS(rc), "archAllocDispatcherPage failed.\n"); rc = DREF(dspFCMRef)->establishPage(dspOffset, dspAddrKern, PAGE_SIZE); tassertMsg(_SUCCESS(rc), "establishPage failed.\n"); dsp = (Dispatcher *) dspAddrKern; dsp->init(dspid); rc = dsp->asyncBufferLocal.storeMsg(_KERNEL_PID, 0, 0, initMsgLength, initMsg); if (_FAILURE(rc)) { (void) DREF(dspFCMRef)->disEstablishPage(dspOffset, PAGE_SIZE); (void) DREF(dspFCMRef)->removeReference(); goto CleanupAndReturn; } (void) dsp->interrupts.fetchAndSet(SoftIntr::ASYNC_MSG); } rc = DREF(hatRef)->getSegmentTable(vp, segTable); tassertMsg(_SUCCESS(rc), "getSegmentTable failed.\n"); pa = new ProcessAnnex(); tassertMsg(pa != NULL, "ProcessAnnex allocation failed.\n"); pa->init(procRef, processID, userMode, isKern, dspUser, dsp, dspFCMRef, dspOffset, segTable, dspid); pa->setEntryPoint(RUN_ENTRY, entry); vpInfo->dspInfo[rd].pa = pa; vpInfo->dspCounter++; InterruptState is; disableHardwareInterrupts(is); exceptionLocal.ipcTargetTable.enter(pa); pa->attach(cda); enableHardwareInterrupts(is); rc = 0; CleanupAndReturn: vpInfo->lock.release(); requests.leave(); return rc; }
SysStatusUval _FD::smallPoll(struct pollfd *fds, uval numfds, sval &timeout) { volatile SysStatusUval rc = 0; SysStatus err = 0; uval ready = 0; SmallPollOp *spo = NULL; uval unmatched = 0; // There will be at most numfds+1 references to this object // 1 per fd being queried plus this function // We have to count ourselves as a reference because we need // to clear spo->result when we exit, so that if any SmallPollNotif // objects are left behind, they can tell that we exited. // (So they won't write to memory that used to be in this stack frame.) spo = new SmallPollOp; spo->refCount = numfds+1; spo->result = &rc; spo->thread = Scheduler::GetCurThread(); lock.acquire(); ready=0; for (uval idx = 0 ; idx < numfds; ++idx) { uval fd = fds[idx].fd; // invalid fd's get marked as INVALID and don't generate an // error on the entire call if (fd > FD_MAX || fd < 0 || !getFD(fd)) { err = _SERROR(2673, 0, EINVAL); break; } fds[idx].revents = 0; FileLinuxRef fileRef = fdrec[fd].ref; // If no good bits set, no need to look at IO object // Otherwise we must assume PollNotif object state is stale GenState avail; avail.state = FileLinux::INVALID; if (fdrec[fd].poll) { avail = fdrec[fd].poll->available; } if (avail.state & fds[idx].events) { DREF(fileRef)->getState(avail); fdrec[fd].poll->available.setIfNewer(avail); } fds[idx].revents = avail.state; // Convert to Linux semantics (EOF-> readable) if (fds[idx].revents & FileLinux::ENDOFFILE) { fds[idx].revents |= FileLinux::READ_AVAIL; } if (fds[idx].revents & fds[idx].events) { ++ready; } else if (ready==0) { // Allocate these things from the spnBuf KeyedNotif *spn = new SmallPollNotif (spo, &fds[idx]); KeyedNotif *previous; SysStatus rc2 = DREF(fileRef)->notifyKeyed(spn, previous); tassertMsg(_SUCCESS(rc2), "handle this\n"); // There was a SmallPollNotif attached from a previous operation // delete it now. // FIXME: We could re-use the existing SmallPollNotif object // (requiring a change of semantics for notifyKeyed), // but this requires handling the races that may occur // as we convert the object to refer to the local "spo". if (_SGETUVAL(rc2) == 1) { delete previous; } unmatched++; } } lock.release(); // Adjust refCount for spo struct. We know how many we refs we created // by creating SmallPollNotif objects (unmatched), and thus // we know that the original refCount was too big (numfds-unmatched). // if (numfds - unmatched) { AtomicAdd(&spo->refCount, ~(numfds - unmatched - 1)); } // We're going to return early, clear spo->result to orphan spo if (err || ready) { spo->result = NULL; // Release the local ref spo->release(); } if (err) return err; if (ready) return ready; // all callbacks set, status of all fds is known // but no fd is ready so block const SysTime start = Scheduler::SysTimeNow(); const SysTime tpus = Scheduler::TicksPerSecond() / 1000000; timeout = timeout * tpus; uval timeToWait = (uval)timeout; uval totalWaited = 0; while (rc == 0 && // if already unblocked (timeToWait!=0) && !SYSCALL_SIGNALS_PENDING()) { SysTime when = ((uval)timeout - totalWaited); TraceOSIOSelBlockTo((timeout - totalWaited)/tpus, (uval)start, Scheduler::GetCurThread()); SYSCALL_DEACTIVATE(); Scheduler::BlockWithTimeout(when, TimerEvent::relative); SYSCALL_ACTIVATE(); SysTime now = Scheduler::SysTimeNow(); totalWaited = now - start; TraceOSIOSelWoke( Scheduler::GetCurThread(), totalWaited/tpus); timeToWait = (uval)timeout - totalWaited; if ((sval)timeToWait<0 && timeout>0) { timeToWait = 0; } else if (timeout==-1) { timeToWait = ~0ULL; } tassertWrn(timeout == -1 || totalWaited < (2*((uval)timeout)), "Excessive wait detected: %ld < %ld\n", totalWaited, 2*(uval)timeout); } // convert back to micro seconds timeout = (sval)(timeToWait/tpus); // Eliminate reference to stack, release the local ref spo->result = NULL; spo->release(); if (rc) return rc; if (timeout!=0) { // Not timed out, no fd's ready --> signal interruption return _SERROR(2922, 0, EINTR); } return 0; }
/* virtual */ SysStatus XHandleTrans::demolish(XHandle xhandle, uval &clientData) { XBaseObj *xBaseObj; ObjRef objRef; BaseProcessRef procRef; SysStatus rc; SysStatusProcessID processPID; // no lock is held, so these pointers can dissapear // out from under us. That's why we copy and test. // also, the xhandle may already be free, so all errors // just lead to returning tassertMsg(XHANDLE_IDX(xhandle) >= CObjGlobals::numReservedEntries, "Freeing global xhandle\n"); xBaseObj = &xhandleTable[XHANDLE_IDX(xhandle)]; objRef = xBaseObj->__iobj; processPID = xBaseObj->getOwnerProcessID(); #ifdef __NO_REGISTER_WITH_KERNEL_WRAPPER #define REGISTER_ALWAYS 0 #else #define REGISTER_ALWAYS 0 #endif if (REGISTER_ALWAYS || (processPID != _KERNEL_PID)) { // we know kernel will not go away, don't insert in process list, // since this ProcessWrapper becomes a hot spot in file systems rc = DREFGOBJ(TheProcessSetRef)-> getRefFromPID(xBaseObj->getOwnerProcessID(), procRef); if (_FAILURE(rc)) { procRef = NULL; } } uval procLocked = 0; tassertMsg(objRef, "No object in XHandleTrans::demolish\n"); rc=DREF(objRef)->publicLockExportedXObjectList(); tassertMsg(rc==0, "Can't lock in XHandleTrans::demolish\n"); if (procRef && (REGISTER_ALWAYS || (processPID != _KERNEL_PID))) { procLocked = DREF(procRef)->lockMatchedXObjectList(); } tassertMsg(xBaseObj->isValid(), "Object is invalid\n"); /* kill xobject so subsequent calls fail don't need a sync - * token circulates before xobj becomes unsafe for stale * references remove from process and object lists. Remove * holder from lists and reset __nummeth to prevent another * releaseAccess call (inflight) from trying to free this * again. */ xBaseObj->__nummeth = 0; if (procRef && (REGISTER_ALWAYS || (processPID != _KERNEL_PID))) { DREF(procRef)->removeMatchedXObj(xhandle); } DREF(objRef)->removeExportedXObj(xhandle); // release locks before callback if (procLocked && (REGISTER_ALWAYS || (processPID != _KERNEL_PID))) { DREF(procRef)->unlockMatchedXObjectList(); } clientData = xBaseObj->getClientData(); DREF(objRef)->publicUnlockExportedXObjectList(); xBaseObj->setBeingFreed(0); // DREF(objRef)->handleXObjFree(xhandle); XBaseObj *removed; // must to this after removes - same space is used for both do { removed = removedEntries; xBaseObj->setNextFree(removed); } while (!CompareAndStoreSynced((uval*)(&removedEntries), (uval)removed, (uval)xBaseObj)); numberRemoved++; // doesn't have to be exact, // so don't sync if ((numberRemoved % XHANDLE_TABLE_GC_INTERVAL) == 0) processToken(); return 0; }
int main(int argc, char *argv[]) { NativeProcess(); const char *optlet = "acA"; int c; int server=0; int alloc_test=0; while ((c = getopt(argc, argv, optlet)) != EOF) { switch (c) { case 'c': server=0; break; case 'a': server=1; break; case 'A': alloc_test =1; break; } } ProcessID pid = DREFGOBJ(TheProcessRef)->getPID(); if (server) { printf("Pid is:%ld\n",pid); startupSecondaryProcessors(); MetaObj::init(); MetaMemTrans::init(); ObjectHandle fake; XHandle partner; MemTransRef mtr; fake.init(); MTHandlerSrv mts(Scheduler::GetCurThread()); SysStatus rc = MemTrans::Create(mtr, fake, 64*PAGE_SIZE, partner, &mts); printf("MemTrans::Create: %016ld\n",rc); if (alloc_test) { #define A(spot,count) (((spot)<<12) | (count)) #define D(spot,count) ((1<<11) | ((spot)<<12) | (count)) uval sequence[15] = { A(0,9), A(1,9), A(2,9), A(3,9), A(4,9), A(5,9), A(6,9), D(1,9), D(3,9), D(2,9), A(1,25), A(2,1), A(3,1),0}; void *allocs[8]={NULL,}; uval slot = 0; while (sequence[slot]!=0) { uval spot = (sequence[slot] & ~((1<<12) - 1))>>12; uval count= sequence[slot] & ((1<<11) - 1); if ( sequence[slot] & 1<<11 ) { DREF(mtr)->freePagePtr(allocs[spot]); printf("Free: %ld %p %ld\n",spot,allocs[spot],count); } else { uval addr; DREF(mtr)->allocPagesLocal(addr, count); allocs[slot]=(void*)addr; printf("Alloc: %ld %p %ld\n",spot,allocs[slot],count); } ++slot; } } mts.waitForNext(); printf("Received connection: %016lx\n",mts.other); mts.waitForNext(); printf("Received ring: %016lx %ld\n",mts.other,mts.ring); for (uval i=0; i<1001; ++i) { while (1) { rc = DREF(mtr)->insertToRing(mts.ring, i); if (_FAILURE(rc)) { printf("insert failure: %016lx\n",rc); mts.waitForNext(); } else { break; } } } } else {
/* virtual */ SysStatusUval FCMPrimitive<PL,ALLOC>::mapPage(uval offset, uval regionVaddr, uval regionSize, AccessMode::pageFaultInfo pfinfo, uval vaddr, AccessMode::mode access, HATRef hat, VPNum vp, RegionRef reg, uval firstAccessOnPP, PageFaultNotification */*fn*/) { SysStatus rc; uval paddr; uval unneededFrameAddr=0; setPFBit(fcmPrimitive); ScopeTime timer(MapPageTimer); /* * we round vaddr down to a pageSize boundary. * thus, pageSize is the smallest pageSize this FCM supports. * for now, its the only size - but we may consider using multiple * page sizes in a single FCM in the future. * Note that caller can't round down since caller may not know * the FCM pageSize. */ vaddr &= -this->pageSize; if (firstAccessOnPP) this->updateRegionPPSet(reg); this->lock.acquire(); offset += vaddr - regionVaddr; //err_printf("FCMPrimitive::mapPage(o %lx, h %lx)\n", offset, hat); MLSStatistics::StartTimer(4); PageDesc *pg = this->findPage(offset); MLSStatistics::DoneTimer(4); if (!pg) { // allocate a new page uval virtAddr; this->lock.release(); rc = DREF(this->pmRef)->allocPages(this->getRef(), virtAddr, this->pageSize, this->pageable); tassert(_SUCCESS(rc), err_printf("woops\n")); this->lock.acquire(); if ((pg = this->findPage(offset)) != 0) { // added in our absence unneededFrameAddr = virtAddr; paddr = pg->paddr; TraceOSMemFCMPrimFoundPage(offset, paddr); } else { paddr = PageAllocatorKernPinned::virtToReal(virtAddr); TraceOSMemFCMPrimMapPage(vaddr, offset, paddr, (uval64)this); pg = this->addPage(offset, paddr, this->pageSize); pg->cacheSynced = PageDesc::SET; DILMA_TRACE_PAGE_DIRTY(this,pg,1); pg->dirty = PageDesc::SET; } } else { paddr = pg->paddr; TraceOSMemFCMPrimFound1Page(offset, paddr); } tassert(1, err_printf(" should use offset %ld\n", offset)); MLSStatistics::StartTimer(5); rc = this->mapPageInHAT(vaddr, pfinfo, access, vp, hat, reg, pg, offset); MLSStatistics::DoneTimer(5); this->lock.release(); /* * do the free not holding a lock for safety sake */ if (unneededFrameAddr != 0) { DREF(this->pmRef)->deallocPages(this->getRef(), unneededFrameAddr, this->pageSize); } return rc; }
// Note, this test doesn't work on powerpc in 32-bit address space mode // in kernel // primitive fcm does not support shared mappings any more // primitiveshared fcm no longer exists void testSharedFCM() { RegionRef regShared1, regShared2, regPriv; FCMRef fcm; uval vaddrShared1, vaddrShared2, vaddrPriv; uval fileOffset; const uval testval = 0x1234321; SysStatus rc; const uval sizeShared = SEGMENT_SIZE + SEGMENT_SIZE; const uval alignShared = SEGMENT_SIZE; const uval sizePriv = PAGE_SIZE + SEGMENT_SIZE; const uval alignPriv = PAGE_SIZE; cprintf(" -- testSharedFCM\n"); #if 0 cprintf(" -- Creating primitive fcm\n"); // test failed attempt to share an FCM rc = FCMPrimitive<PageList<AllocGlobal>,AllocGlobal>::Create(fcm); tassert(_SUCCESS(rc), err_printf("oops\n")); cprintf(" -- trying failed attempt to access shared\n"); rc = RegionDefault::CreateFixedLen(regShared1, GOBJK(TheProcessRef), vaddrShared1, sizeShared, alignShared, fcm, 0, AccessMode::writeUserWriteSup); err_printf(" -- verify failure message above\n"); tassert(_SUCCESS(rc), err_printf("ooops\n")); cprintf(" -- Destroying region\n"); rc = DREF(regShared1)->destroy(); tassert(_SUCCESS(rc), err_printf("oops\n")); cprintf(" -- Destroying fcm\n"); rc = DREF(fcm)->destroy(); tassert(_SUCCESS(rc), err_printf("oops\n")); #endif cprintf("\n -- Creating fcm\n"); rc = FCMPrimitiveShared::Create(fcm); tassert(_SUCCESS(rc), err_printf("oops\n")); cprintf("\n -- Creating region using non-shared mode\n"); rc = RegionDefault::CreateFixedLen(regPriv, GOBJK(TheProcessRef), vaddrPriv, PAGE_SIZE, alignShared, fcm, 0, AccessMode::writeUserWriteSup); tassert(_SUCCESS(rc), err_printf("oops\n")); cprintf(" -- Got region at %lx size %lx\n", vaddrPriv, sizePriv); cprintf(" -- Accessing non-shared region at %lx\n", vaddrPriv); *(volatile uval *)vaddrPriv; cprintf(" -- Destroying non-shared region\n"); rc = DREF(regPriv)->destroy(); tassert(_SUCCESS(rc), err_printf("oops\n")); cprintf("\n -- Creating region using shared mode\n"); rc = RegionDefault::CreateFixedLen(regShared1, GOBJK(TheProcessRef), vaddrShared1, sizeShared, alignShared, fcm, 0, AccessMode::writeUserWriteSup); tassert(_SUCCESS(rc), err_printf("oops\n")); cprintf(" -- Got region at %lx size %lx\n", vaddrShared1, sizeShared); cprintf(" -- Creating read-only region using shared mode\n"); rc = RegionDefault::CreateFixedLen(regShared2, GOBJK(TheProcessRef), vaddrShared2, sizeShared, alignShared, fcm, 0, AccessMode::readUserReadSup); tassert(_SUCCESS(rc), err_printf("oops\n")); cprintf(" -- Got region at %lx size %lx\n", vaddrShared2, sizeShared); cprintf("\n -- Accessing shared region at %lx\n", vaddrShared1); *(volatile uval *)vaddrShared1 = testval; cprintf(" -- Accessing shared region at %lx\n", vaddrShared1 + PAGE_SIZE); *(volatile uval *)(vaddrShared1+PAGE_SIZE) = testval+1; cprintf(" -- Accessing shared region at %lx\n", vaddrShared1+SEGMENT_SIZE); *(volatile uval *)(vaddrShared1+SEGMENT_SIZE) = testval+2; cprintf(" -- Accessing shared region at %lx\n", vaddrShared1+SEGMENT_SIZE); *(volatile uval *)(vaddrShared1+SEGMENT_SIZE); cprintf(" -- Accessing read-only shared region at %lx\n", vaddrShared2); *(volatile uval *)vaddrShared2; cprintf("\n -- Creating region using non-shared mode\n"); rc = RegionDefault::CreateFixedLen(regPriv, GOBJK(TheProcessRef), vaddrPriv, sizePriv, alignPriv, fcm, 0, AccessMode::writeUserWriteSup); tassert(_SUCCESS(rc), err_printf("oops\n")); cprintf(" -- Got region at %lx size %lx\n", vaddrPriv, sizePriv); tassert(vaddrShared1 != vaddrPriv, err_printf("shared == priv\n")); cprintf("\n -- Accessing non-shared region at %lx\n", vaddrPriv); if (*(volatile uval *)vaddrPriv != testval) { err_printf("Bad value at %lx: 0x%lx != %lx\n", vaddrPriv, *(volatile uval *)vaddrPriv, testval); passert(0, err_printf("oops\n")); } *(volatile uval *)(vaddrPriv); cprintf(" -- Accessing non-shared region at %lx\n",vaddrPriv+SEGMENT_SIZE); if (*(volatile uval *)(vaddrPriv+SEGMENT_SIZE) != testval+2) { err_printf("Bad value at %lx: 0x%lx != %lx\n", vaddrPriv+SEGMENT_SIZE, *(volatile uval *)(vaddrPriv+SEGMENT_SIZE), testval+2); passert(0, err_printf("oops\n")); } fileOffset = 0; cprintf("\n -- unmapping page %lx\n", fileOffset); rc = DREF((FCMPrimitiveShared **)fcm)->unmapPage(fileOffset); tassert(_SUCCESS(rc), err_printf("oops\n")); cprintf(" -- Accessing shared region at %lx\n", vaddrShared1); *(volatile uval *)vaddrShared1; cprintf(" -- Accessing shared region at %lx\n", vaddrShared1 + PAGE_SIZE); *(volatile uval *)(vaddrShared1+PAGE_SIZE); cprintf(" -- Accessing shared region at %lx\n", vaddrShared1+SEGMENT_SIZE); *(volatile uval *)(vaddrShared1+SEGMENT_SIZE); cprintf(" -- Accessing non-shared region at %lx\n", vaddrPriv); if (*(volatile uval *)vaddrPriv != testval) { err_printf("Bad value at %lx: 0x%lx != %lx\n", vaddrPriv, *(volatile uval *)vaddrPriv, testval); passert(0, err_printf("oops\n")); } cprintf(" -- Accessing read-only shared region at %lx\n", vaddrShared2); *(volatile uval *)vaddrShared2; fileOffset = SEGMENT_SIZE; cprintf("\n -- unmapping page %lx\n", fileOffset); rc = DREF((FCMPrimitiveShared **)fcm)->unmapPage(fileOffset); tassert(_SUCCESS(rc), err_printf("oops\n")); cprintf(" -- Accessing shared region at %lx\n", vaddrShared1); *(volatile uval *)vaddrShared1; cprintf(" -- Accessing shared region at %lx\n", vaddrShared1 + PAGE_SIZE); *(volatile uval *)(vaddrShared1+PAGE_SIZE); cprintf(" -- Accessing shared region at %lx\n", vaddrShared1+SEGMENT_SIZE); *(volatile uval *)(vaddrShared1+SEGMENT_SIZE); cprintf(" -- Accessing non-shared region at %lx\n",vaddrPriv+SEGMENT_SIZE); if (*(volatile uval *)(vaddrPriv+SEGMENT_SIZE) != testval+2) { err_printf("Bad value at %lx: 0x%lx != %lx\n", vaddrPriv+SEGMENT_SIZE, *(volatile uval *)(vaddrPriv+SEGMENT_SIZE), testval+2); passert(0, err_printf("oops\n")); } cprintf("\n -- Destroying shared region\n"); rc = DREF(regShared1)->destroy(); tassert(_SUCCESS(rc), err_printf("oops\n")); cprintf(" -- Creating region using shared mode\n"); rc = RegionDefault::CreateFixedLen(regShared1, GOBJK(TheProcessRef), vaddrShared1, sizeShared, alignShared, fcm, 0, AccessMode::writeUserWriteSup); tassert(_SUCCESS(rc), err_printf("oops\n")); cprintf(" -- Got region at %lx size %lx\n", vaddrShared1, sizeShared); cprintf("\n -- Accessing shared region at %lx\n", vaddrShared1); *(volatile uval *)vaddrShared1; cprintf(" -- Accessing shared region at %lx\n", vaddrShared1 + PAGE_SIZE); *(volatile uval *)(vaddrShared1+PAGE_SIZE); cprintf(" -- Accessing non-shared region at %lx\n", vaddrPriv); if (*(volatile uval *)vaddrPriv != testval) { err_printf("Bad value at %lx: 0x%lx != %lx\n", vaddrPriv, *(volatile uval *)vaddrPriv, testval); passert(0, err_printf("oops\n")); } cprintf("\n -- Destroying non-shared region\n"); rc = DREF(regPriv)->destroy(); tassert(_SUCCESS(rc), err_printf("oops\n")); cprintf(" -- Destroying shared region\n"); rc = DREF(regShared1)->destroy(); tassert(_SUCCESS(rc), err_printf("oops\n")); cprintf(" -- Destroying read-only shared region\n"); rc = DREF(regShared2)->destroy(); tassert(_SUCCESS(rc), err_printf("oops\n")); #if 0 // verify fault fails after destroying region cprintf(" -- Accessing region after removal; should fail\n"); *(volatile uval *)vaddrShared1 = 0; #endif cprintf(" -- Destroying fcm\n"); rc = DREF(fcm)->destroy(); tassert(_SUCCESS(rc), err_printf("oops\n")); cprintf("testSharedFCM all done\n"); }
SysStatus HATDefaultBase<ALLOC>::destroy(void) { //err_printf("HATDefaultBase %p destroying\n", getRef()); { // remove all ObjRefs to this object SysStatus rc=closeExportedXObjectList(); // most likely cause is that another destroy is in progress // in which case we return success if (_FAILURE(rc)) return _SCLSCD(rc)==1?0:rc; } SysStatus rc=0; VPSet* dummy; //Get rid of all the segments SegmentList<ALLOC>* restart; SegmentHATRef ref; //Use region logic, setting region bounds to all of memory uval regionAddr = 0; uval regionEnd = (uval)(-1); uval segmentAddr, segmentEnd; uval vp; /* * clean up the global list */ glock.acquire(); // regionAddr is updated by delete to be correct for this segment restart = &segmentList; while (0<=(rc=SegmentList<ALLOC>::DeleteSegment(regionAddr, regionEnd, segmentAddr, segmentEnd, ref, dummy, restart))) { tassert(rc==0,err_printf("Impossible in HATDefaultBase::destroy()\n")); //err_printf("HATDefaultBase %p destroying seg %p\n", getRef(), ref); DREF(ref)->destroy(); } glock.release(); for (vp=0;vp<Scheduler::VPLimit;vp++) { byVP[vp].lock.acquire(); // Free segment table if (byVP[vp].segps) { //err_printf("HATDefaultBase %p destroying segtable %p on %ld\n", // getRef(), byVP[vp].segps, vp); byVP[vp].segps->destroy(); } // Free local copy of segmentHAT list restart = &(byVP[vp].segmentList); while (0<=(rc=SegmentList<ALLOC>::DeleteSegment(regionAddr, regionEnd, segmentAddr, segmentEnd, ref, dummy, restart))); byVP[vp].lock.release(); } // schedule the object for deletion destroyUnchecked(); return 0; }
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count) { SysStatus rc; SYSCALL_ENTER(); uval addr; uval maxcount; uval inOffset; ObjectHandle frOH; // try to map the input file struct stat stat_buf; FileLinuxRef inFileRef, outFileRef; inOffset = *offset; inFileRef = _FD::GetFD(in_fd); if (!inFileRef) { SYSCALL_EXIT(); return -EBADF; } outFileRef = _FD::GetFD(out_fd); if (!outFileRef) { SYSCALL_EXIT(); return -EBADF; } // no get the object handle to the FR rc = DREF(inFileRef)->getFROH(frOH, FileLinux::DEFAULT); if (_FAILURE(rc)) { //FIXME - do a copy if we can't map the input file // this happens if the input is a stream or other funny // read the man page and remember to reset the in cursor SYSCALL_EXIT(); return -EBADF; } // find out how long the input file is, incase count is too big rc = DREF(inFileRef)->getStatus( FileLinux::Stat::FromStruc(&stat_buf)); if (_FAILURE(rc)) { SYSCALL_EXIT(); return -_SGENCD(rc); } maxcount = (uval)stat_buf.st_size-inOffset; if (count>maxcount) count = maxcount; // always map the whole file. offset might not be page aligned rc = StubRegionDefault::_CreateFixedLenExt( addr, inOffset+count, 0, frOH, 0, AccessMode::readUserReadSup, 0, RegionType::K42Region); if (_FAILURE(rc)) { SYSCALL_EXIT(); return -_SGENCD(rc); } // now deal with output file uval inAddr, inCount; inAddr = addr+inOffset; // read pointer in mapped region inCount = count; // amount left to write uval doBlock = ~(DREF(outFileRef)->getFlags()) & O_NONBLOCK; ThreadWait *tw = NULL; ThreadWait **ptw = NULL; if (doBlock) { ptw = &tw; } while (inCount > 0) { GenState moreAvail; rc=DREF(outFileRef)->write((char *)inAddr, inCount, ptw, moreAvail); if (_SUCCESS(rc)) { // wrote something inCount -= _SGETUVAL(rc); inAddr += _SGETUVAL(rc); rc = count; // incase we are done } else if (tw) { while (!tw->unBlocked()) { SYSCALL_BLOCK(); #if 0 //FIXME - is sendfile interupptable - I hope not but ... // if it is must fix up return values if (SYSCALL_SIGNALS_PENDING()) { SYSCALL_EXIT(); return -EINTR; } #endif } tw->destroy(); delete tw; tw = NULL; } else { rc = -_SGENCD(rc); goto finished; } } finished: // clean up region and return DREFGOBJ(TheProcessRef)->regionDestroy(addr); *offset = (off_t)(inAddr - addr); SYSCALL_EXIT(); return rc; }
/* * Display a dialog box with a list of options that can be turned on or off */ int dialog_checklist(unsigned char *title, unsigned char *prompt, int height, int width, int list_height, int cnt, void *it, unsigned char *result) { int i, j, x, y, cur_x, cur_y, old_x, old_y, box_x, box_y, key = 0, button, choice, l, k, scroll, max_choice, item_no = 0, *status; int redraw_menu = FALSE, cursor_reset = FALSE; int rval = 0, onlist = 1, ok_space, cancel_space; char okButton, cancelButton; WINDOW *dialog, *list; unsigned char **items = NULL; dialogMenuItem *ditems; int list_width, check_x, item_x; /* Allocate space for storing item on/off status */ if ((status = alloca(sizeof(int) * abs(cnt))) == NULL) { endwin(); fprintf(stderr, "\nCan't allocate memory in dialog_checklist().\n"); exit(-1); } draw: choice = scroll = button = 0; /* Previous calling syntax, e.g. just a list of strings? */ if (cnt >= 0) { items = it; ditems = NULL; item_no = cnt; /* Initializes status */ for (i = 0; i < item_no; i++) status[i] = !strcasecmp(items[i*3 + 2], "on"); } /* It's the new specification format - fake the rest of the code out */ else { item_no = abs(cnt); ditems = it; if (!items) items = (unsigned char **)alloca((item_no * 3) * sizeof(unsigned char *)); /* Initializes status */ for (i = 0; i < item_no; i++) { status[i] = ditems[i].checked ? ditems[i].checked(&ditems[i]) : FALSE; items[i*3] = ditems[i].prompt; items[i*3 + 1] = ditems[i].title; items[i*3 + 2] = status[i] ? "on" : "off"; } } max_choice = MIN(list_height, item_no); check_x = 0; item_x = 0; /* Find length of longest item in order to center checklist */ for (i = 0; i < item_no; i++) { l = strlen(items[i*3]); for (j = 0; j < item_no; j++) { k = strlen(items[j*3 + 1]); check_x = MAX(check_x, l + k + 6); } item_x = MAX(item_x, l); } if (height < 0) height = strheight(prompt)+list_height+4+2; if (width < 0) { i = strwidth(prompt); j = ((title != NULL) ? strwidth(title) : 0); width = MAX(i,j); width = MAX(width,check_x+4)+4; } width = MAX(width,24); if (width > COLS) width = COLS; if (height > LINES) height = LINES; /* center dialog box on screen */ x = (COLS - width)/2; y = (LINES - height)/2; #ifdef HAVE_NCURSES if (use_shadow) draw_shadow(stdscr, y, x, height, width); #endif dialog = newwin(height, width, y, x); if (dialog == NULL) { endwin(); fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n", height,width, y, x); return -1; } keypad(dialog, TRUE); draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr); wattrset(dialog, border_attr); wmove(dialog, height-3, 0); waddch(dialog, ACS_LTEE); for (i = 0; i < width-2; i++) waddch(dialog, ACS_HLINE); wattrset(dialog, dialog_attr); waddch(dialog, ACS_RTEE); wmove(dialog, height-2, 1); for (i = 0; i < width-2; i++) waddch(dialog, ' '); if (title != NULL) { wattrset(dialog, title_attr); wmove(dialog, 0, (width - strlen(title))/2 - 1); waddch(dialog, ' '); waddstr(dialog, title); waddch(dialog, ' '); } wattrset(dialog, dialog_attr); wmove(dialog, 1, 2); print_autowrap(dialog, prompt, height - 1, width - 2, width, 1, 2, TRUE, FALSE); list_width = width - 6; getyx(dialog, cur_y, cur_x); box_y = cur_y + 1; box_x = (width - list_width) / 2 - 1; /* create new window for the list */ list = subwin(dialog, list_height, list_width, y + box_y + 1, x + box_x + 1); if (list == NULL) { delwin(dialog); endwin(); fprintf(stderr, "\nsubwin(dialog,%d,%d,%d,%d) failed, maybe wrong dims\n", list_height, list_width, y + box_y + 1, x + box_x + 1); return -1; } keypad(list, TRUE); /* draw a box around the list items */ draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2, menubox_border_attr, menubox_attr); check_x = (list_width - check_x) / 2; item_x = check_x + item_x + 6; /* Print the list */ for (i = 0; i < max_choice; i++) print_item(list, items[i * 3], items[i * 3 + 1], status[i], i, i == choice, DREF(ditems, i), list_width, item_x, check_x); wnoutrefresh(list); print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y); display_helpline(dialog, height - 1, width); x = width / 2 - 11; y = height - 2; /* Is this a fancy new style argument string where we get to override * the buttons, or an old style one where they're fixed? */ if (ditems && result) { cancelButton = toupper(ditems[CANCEL_BUTTON].prompt[0]); print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : FALSE); okButton = toupper(ditems[OK_BUTTON].prompt[0]); print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : TRUE); } else { cancelButton = 'C'; print_button(dialog, "Cancel", y, x + 14, FALSE); okButton = 'O'; print_button(dialog, " OK ", y, x, TRUE); } wnoutrefresh(dialog); wmove(list, choice, check_x+1); wrefresh(list); /* * XXX Black magic voodoo that allows printing to the checklist * window. For some reason, if this "refresh" code is not in * place, printing to the window from the selected callback * prints "behind" the checklist window. There is probably a * better way to do this. */ draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2, menubox_border_attr, menubox_attr); for (i = 0; i < max_choice; i++) print_item(list, items[i * 3], items[i * 3 + 1], status[i], i, i == choice, DREF(ditems, i), list_width, item_x, check_x); print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y); wmove(list, choice, check_x+1); wnoutrefresh(dialog); wrefresh(list); /* XXX Black magic XXX */ while (key != ESC) { key = wgetch(dialog); /* Shortcut to OK? */ if (toupper(key) == okButton) { if (ditems) { if (result && ditems[OK_BUTTON].fire) { int st; WINDOW *save; save = dupwin(newscr); st = ditems[OK_BUTTON].fire(&ditems[OK_BUTTON]); if (st & DITEM_RESTORE) { touchwin(save); wrefresh(save); } delwin(save); } } else if (result) { *result = '\0'; for (i = 0; i < item_no; i++) { if (status[i]) { strcat(result, items[i*3]); strcat(result, "\n"); } } } rval = 0; key = ESC; /* Lemme out! */ break; } /* Shortcut to cancel? */ if (toupper(key) == cancelButton) { if (ditems && result && ditems[CANCEL_BUTTON].fire) { int st; WINDOW *save; save = dupwin(newscr); st = ditems[CANCEL_BUTTON].fire(&ditems[CANCEL_BUTTON]); if (st & DITEM_RESTORE) { touchwin(save); wrefresh(save); wmove(dialog, cur_y, cur_x); } delwin(save); } rval = 1; key = ESC; /* I gotta go! */ break; } /* Check if key pressed matches first character of any item tag in list */ for (i = 0; i < max_choice; i++) if (key != ' ' && key < 0x100 && toupper(key) == toupper(items[(scroll+i)*3][0])) break; if (i < max_choice || (key >= '1' && key <= MIN('9', '0'+max_choice)) || KEY_IS_UP(key) || KEY_IS_DOWN(key) || ((key == ' ' || key == '\n' || key == '\r') && onlist)) { /* if moving from buttons to the list, reset and redraw buttons */ if (!onlist) { onlist = 1; button = 0; if (ditems && result) { print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button); print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button); } else { print_button(dialog, "Cancel", y, x + 14, button); print_button(dialog, " OK ", y, x, !button); } wmove(list, choice, check_x+1); wnoutrefresh(dialog); wrefresh(list); } if (key >= '1' && key <= MIN('9', '0'+max_choice)) i = key - '1'; else if (KEY_IS_UP(key)) { if (!choice) { if (scroll) { /* Scroll list down */ getyx(dialog, cur_y, cur_x); /* Save cursor position */ if (list_height > 1) { /* De-highlight current first item before scrolling down */ print_item(list, items[scroll * 3], items[scroll * 3 + 1], status[scroll], 0, FALSE, DREF(ditems, scroll), list_width, item_x, check_x); scrollok(list, TRUE); wscrl(list, -1); scrollok(list, FALSE); } scroll--; print_item(list, items[scroll*3], items[scroll*3 + 1], status[scroll], 0, TRUE, DREF(ditems, scroll), list_width, item_x, check_x); print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y); wmove(list, choice, check_x+1); wnoutrefresh(dialog); wrefresh(list); } continue; /* wait for another key press */ } else i = choice - 1; } else if (KEY_IS_DOWN(key)) { if (choice == max_choice - 1) { if (scroll + choice < item_no - 1) { /* Scroll list up */ getyx(dialog, cur_y, cur_x); /* Save cursor position */ if (list_height > 1) { /* De-highlight current last item before scrolling up */ print_item(list, items[(scroll + max_choice - 1) * 3], items[(scroll + max_choice - 1) * 3 + 1], status[scroll + max_choice - 1], max_choice - 1, FALSE, DREF(ditems, scroll + max_choice - 1), list_width, item_x, check_x); scrollok(list, TRUE); scroll(list); scrollok(list, FALSE); } scroll++; print_item(list, items[(scroll + max_choice - 1) * 3], items[(scroll + max_choice - 1) * 3 + 1], status[scroll + max_choice - 1], max_choice - 1, TRUE, DREF(ditems, scroll + max_choice - 1), list_width, item_x, check_x); print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y); wmove(list, choice, check_x+1); wnoutrefresh(dialog); wrefresh(list); } continue; /* wait for another key press */ } else i = choice + 1; } else if ((key == ' ' || key == '\n' || key == '\r') && onlist) { /* Toggle item status */ char lbra = 0, rbra = 0, mark = 0; getyx(list, old_y, old_x); /* Save cursor position */ if (ditems) { if (ditems[scroll + choice].fire) { int st; WINDOW *save; save = dupwin(newscr); st = ditems[scroll + choice].fire(&ditems[scroll + choice]); /* Call "fire" action */ if (st & DITEM_RESTORE) { touchwin(save); wrefresh(save); } delwin(save); if (st & DITEM_REDRAW) { wclear(list); for (i = 0; i < item_no; i++) status[i] = ditems[i].checked ? ditems[i].checked(&ditems[i]) : FALSE; for (i = 0; i < max_choice; i++) { print_item(list, items[(scroll + i) * 3], items[(scroll + i) * 3 + 1], status[scroll + i], i, i == choice, DREF(ditems, scroll + i), list_width, item_x, check_x); } wnoutrefresh(list); print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y); wrefresh(dialog); } if (st & DITEM_LEAVE_MENU) { /* Allow a fire action to take us out of the menu */ key = ESC; rval = 0; break; } else if (st & DITEM_RECREATE) { delwin(list); delwin(dialog); dialog_clear(); goto draw; } } status[scroll + choice] = ditems[scroll + choice].checked ? ditems[scroll + choice].checked(&ditems[scroll + choice]) : FALSE; lbra = ditems[scroll + choice].lbra; rbra = ditems[scroll + choice].rbra; mark = ditems[scroll + choice].mark; } else status[scroll + choice] = !status[scroll + choice]; wmove(list, choice, check_x); wattrset(list, check_selected_attr); if (!lbra) lbra = '['; if (!rbra) rbra = ']'; if (!mark) mark = 'X'; wprintw(list, "%c%c%c", lbra, status[scroll + choice] ? mark : ' ', rbra); wmove(list, old_y, old_x); /* Restore cursor to previous position */ wrefresh(list); continue; /* wait for another key press */ } if (i != choice) { /* De-highlight current item */ getyx(dialog, cur_y, cur_x); /* Save cursor position */ print_item(list, items[(scroll + choice) * 3], items[(scroll + choice) * 3 + 1], status[scroll + choice], choice, FALSE, DREF(ditems, scroll + choice), list_width, item_x, check_x); /* Highlight new item */ choice = i; print_item(list, items[(scroll + choice) * 3], items[(scroll + choice) * 3 + 1], status[scroll + choice], choice, TRUE, DREF(ditems, scroll + choice), list_width, item_x, check_x); wmove(list, choice, check_x+1); /* Restore cursor to previous position */ wrefresh(list); } continue; /* wait for another key press */ } switch (key) { case KEY_PPAGE: /* can we go up? */ if (scroll > height - 4) scroll -= (height-4); else scroll = 0; redraw_menu = TRUE; if (!onlist) { onlist = 1; button = 0; } break; case KEY_NPAGE: /* can we go down a full page? */ if (scroll + list_height >= item_no-1 - list_height) { scroll = item_no - list_height; if (scroll < 0) scroll = 0; } else scroll += list_height; redraw_menu = TRUE; if (!onlist) { onlist = 1; button = 0; } break; case KEY_HOME: /* go to the top */ scroll = 0; choice = 0; redraw_menu = TRUE; cursor_reset = TRUE; onlist = 1; break; case KEY_END: /* Go to the bottom */ scroll = item_no - list_height; if (scroll < 0) scroll = 0; choice = max_choice - 1; redraw_menu = TRUE; cursor_reset = TRUE; onlist = 1; break; case TAB: case KEY_BTAB: /* move to next component */ if (onlist) { /* on list, next is ok button */ onlist = 0; if (ditems && result) { print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button); print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button); ok_space = 1; cancel_space = strlen(ditems[OK_BUTTON].prompt) + 6; } else { print_button(dialog, "Cancel", y, x + 14, button); print_button(dialog, " OK ", y, x, !button); ok_space = 3; cancel_space = 15; } if (button) wmove(dialog, y, x + cancel_space); else wmove(dialog, y, x + ok_space); wrefresh(dialog); break; } else if (button) { /* on cancel button, next is list */ button = 0; onlist = 1; redraw_menu = TRUE; break; } /* on ok button, next is cancel button, same as left/right case */ case KEY_LEFT: case KEY_RIGHT: onlist = 0; button = !button; if (ditems && result) { print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button); print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button); ok_space = 1; cancel_space = strlen(ditems[OK_BUTTON].prompt) + 6; } else { print_button(dialog, "Cancel", y, x + 14, button); print_button(dialog, " OK ", y, x, !button); ok_space = 3; cancel_space = 15; } if (button) wmove(dialog, y, x + cancel_space); else wmove(dialog, y, x + ok_space); wrefresh(dialog); break; case ' ': case '\n': case '\r': if (!onlist) { if (ditems) { if (result && ditems[button ? CANCEL_BUTTON : OK_BUTTON].fire) { int st; WINDOW *save = dupwin(newscr); st = ditems[button ? CANCEL_BUTTON : OK_BUTTON].fire(&ditems[button ? CANCEL_BUTTON : OK_BUTTON]); if (st & DITEM_RESTORE) { touchwin(save); wrefresh(save); } delwin(save); if (st == DITEM_FAILURE) continue; } } else if (result) { *result = '\0'; for (i = 0; i < item_no; i++) { if (status[i]) { strcat(result, items[i*3]); strcat(result, "\n"); } } } rval = button; key = ESC; /* Bail out! */ break; } /* Let me outta here! */ case ESC: rval = -1; break; /* Help! */ case KEY_F(1): case '?': display_helpfile(); break; } if (redraw_menu) { getyx(list, old_y, old_x); wclear(list); /* * Re-draw a box around the list items. It is required * if amount of list items is smaller than height of listbox. * Otherwise un-redrawn field will be filled with default * screen attributes instead of dialog attributes. */ draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2, menubox_border_attr, menubox_attr); for (i = 0; i < max_choice; i++) print_item(list, items[(scroll + i) * 3], items[(scroll + i) * 3 + 1], status[scroll + i], i, i == choice, DREF(ditems, scroll + i), list_width, item_x, check_x); print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y); /* redraw buttons to fix highlighting */ if (ditems && result) { print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button); print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button); } else { print_button(dialog, "Cancel", y, x + 14, button); print_button(dialog, " OK ", y, x, !button); } wnoutrefresh(dialog); if (cursor_reset) { wmove(list, choice, check_x+1); cursor_reset = FALSE; } else { wmove(list, old_y, old_x); } wrefresh(list); redraw_menu = FALSE; } } delwin(list); delwin(dialog); return rval; }
extern "C" SysStatus ExceptionLocal_PgfltHandler(ProcessAnnex *srcProc, uval faultInfo, uval faultAddr, uval noReflection) { SysStatus rc; uval wasActive; PageFaultNotification *pn; #ifdef COLLECT_FAULT_STATS //So that setPFBit works right uval oldTSU = Scheduler::GetThreadSpecificUvalSelf(); Scheduler::SetThreadSpecificUvalSelf(0); #endif // COLLECT_FAULT_STATS TraceOSExceptionPgflt((uval64) CurrentThread, faultAddr, (uval64) srcProc->commID, (uval64) srcProc->excStatePtr()->codeAddr(), (uval64) faultInfo); #ifndef NDEBUG /* * Check for segment fault in borrowed kernel address space. */ if (exceptionLocal.currentSegmentTable-> checkKernelSegmentFault(faultAddr)) { //FIXME - its hard to test this code //This printf because Marc wants to know if this //code ever gets executed err_printf("Tell Marc: segment fault %lx k %x\n", faultAddr, srcProc->isKernel); return 0; // we may re-fault for the page itself } #endif StatTimer t1(ExceptionCode); PRESERVE_PPC_PAGE(); enableHardwareInterrupts(); tassertMsg(faultAddr!=checkAddr,"got it\n"); #ifdef COLLECT_FAULT_STATS if (faultInfo & DSIStatusReg::writeFault) { setPFBit(NeedWrite); } #endif // COLLECT_FAULT_STATS wasActive = CurrentThread->isActive(); if (!wasActive) { CurrentThread->activate(); } if (noReflection) { pn = NULL; } else { pn = srcProc->fnMgr.alloc(srcProc); #ifndef NDEBUG if (pn != NULL) pn->vaddr = faultAddr; #endif } rc = DREF(srcProc->processRef)-> handleFault(faultInfo, faultAddr, pn, SysTypes::VP_FROM_COMMID(srcProc->commID)); // Free the notification object for bad-address or in-core page faults. if ((pn != NULL) && (_FAILURE(rc) || (_SGETUVAL(rc) == 0))) { srcProc->fnMgr.free(pn); } if (!wasActive) { CurrentThread->deactivate(); } tassertWrn(srcProc->isKernel || _SUCCESS(rc), "User-mode bad-address fault: " "commID 0x%lx, pc %p, addr %lx, rc %lx.\n", srcProc->commID, srcProc->excStatePtr()->codeAddr(), faultAddr, rc); disableHardwareInterrupts(); RESTORE_PPC_PAGE(); t1.record(); TraceOSExceptionPgfltDone((uval) srcProc->commID, (uval64) CurrentThread, faultAddr, rc, Scheduler::GetThreadSpecificUvalSelf()); #ifdef COLLECT_FAULT_STATS Scheduler::SetThreadSpecificUvalSelf(oldTSU); #endif // COLLECT_FAULT_STATS return rc; }
SysStatusUval FCMDefault::locked_giveBack(uval numPages) { _ASSERT_HELD(lock); //N.B. these arrays are on the stack, so they must be kept small FreeFrameList ffl; uval tmp=0; uval totalReturned = 0; PageDesc *pg; SysStatus rc; if (beingDestroyed) { // we are being destroyed now, so info is soon to be useless return -1; } while (totalReturned < numPages) { if (pendingWrite) { pg = pageList.dequeueFreeList(PageDesc::DQ_CLEAN); } else { pg = pageList.dequeueFreeList(PageDesc::DQ_HEAD); } if (pg == NULL) break; //N.B. can be doingIO, for example if fsync has happened tassert(!pg->mapped, err_printf("oops\n")); tassert(!pg->established, err_printf("oops\n")); pg->free = PageDesc::CLEAR; totalReturned+=pageSize/PAGE_SIZE; if (pg->doingIO) { pg->freeAfterIO = PageDesc::SET; } else if (pg->dirty) { pg->doingIO = PageDesc::SET; DILMA_TRACE_PAGE_DIRTY(this,pg,-1); pg->dirty = PageDesc::CLEAR; pg->freeAfterIO = PageDesc::SET; tassertMsg( (pendingWrite == NULL), "woops\n"); #ifdef USE_RESUME pendingWrite = pg; #endif lock.release(); #ifdef USE_RESUME rc=DREF(frRef)->startPutPage(pg->paddr, pg->fileOffset, rq); #else rc=DREF(frRef)->startPutPage(pg->paddr, pg->fileOffset); #endif lock.acquire(); if (_SUCCESS(rc)) { pendingWrite = 0; } else if (_FAILURE(rc) && (_SCLSCD(rc) != FR::WOULDBLOCK)) { passertMsg(0, "woops"); } } else { // clean page tmp = PageAllocatorKernPinned::realToVirt(pg->paddr); //FIXME maa do we need sizes in free frame list // would be nice to release lock here, but then must do // pageList.remove before dealloc tassertMsg(0==pg->fn, "notify should have been done\n"); pageList.remove(pg->fileOffset); lock.release(); DREF(pmRef)->deallocPages(getRef(), tmp, pageSize); lock.acquire(); } } return totalReturned; }
extern "C" SysStatus ExceptionLocal_IPCRemote(IPCRegsArch *ipcRegsP, CommID targetID, uval ipcType, ProcessAnnex *srcProc) { uval len, checkedLen; uval ipcBufSize; RemoteIPCBuffer **listp, *list, *ipcBuf; SysStatus rc; BaseProcessRef pref; TraceOSExceptionIPCRemote( (uval64) CurrentThread, ipcType, targetID); enableHardwareInterrupts(); CurrentThread->activate(); // Deallocate any remote IPC buffers that have been returned here. listp = &ExceptionLocal::OldRemoteIPCBuffers[exceptionLocal.vp]; list = (RemoteIPCBuffer *) FetchAndClear((uval *) listp); while (list != NULL) { ipcBuf = list; list = list->next; AllocPinnedGlobalPadded::free(ipcBuf, ipcBuf->size); } len = GET_PPC_LENGTH(); checkedLen = (len <= PPCPAGE_LENGTH_MAX) ? len : PPCPAGE_LENGTH_MAX; ipcBufSize = sizeof(RemoteIPCBuffer) + checkedLen; ipcBuf = (RemoteIPCBuffer *) AllocPinnedGlobalPadded::alloc(ipcBufSize); if (ipcBuf != NULL) { // remember source and size for deallocation ipcBuf->sourceVP = exceptionLocal.vp; ipcBuf->size = ipcBufSize; ipcBuf->ipcType = ipcType; ipcBuf->callerID = srcProc->commID; ipcBuf->ipcRegs = *ipcRegsP; ipcBuf->ipcPageLength = len; memcpy((char *) (ipcBuf + 1), PPCPAGE_DATA, checkedLen); RESET_PPC(); // Find the process that matches targetID, and call it. rc = DREFGOBJ(TheProcessSetRef)-> getRefFromPID(SysTypes::PID_FROM_COMMID(targetID), pref); if (_SUCCESS(rc)) { rc = DREF((ProcessRef) pref)->sendRemoteIPC(targetID, ipcBuf); } if (_FAILURE(rc)) { /* * Restore the PPC page and deallocate the ipcBuffer if the * remote call failed. If it succeeded, the target end is * responsible for the buffer and its content. */ SET_PPC_LENGTH(len); memcpy(PPCPAGE_DATA, (char *) (ipcBuf + 1), checkedLen); AllocPinnedGlobalPadded::free(ipcBuf, ipcBufSize); /* * Add ipcType into the return code, so that the sender's IPC * fault handler will know how to process the fault. */ rc = _SERROR(_SERRCD(rc), ipcType, _SGENCD(rc)); } } else { rc = _SERROR(2310, ipcType, EAGAIN); } CurrentThread->deactivate(); disableHardwareInterrupts(); if (_FAILURE(rc) && (_SGENCD(rc) == EAGAIN)) { exceptionLocal.ipcRetryManager. requestNotificationRemote(srcProc, targetID); } TraceOSExceptionIPCRemoteDone(srcProc->commID); return rc; }
SysStatus FileLinuxFile::locked_registerCallBackUseType() { FLFDEBUG("locked_registerCallBackUseType"); _ASSERT_HELD(streamLock); tassertMsg(callBackUseTypeRegistered==0, "registered already?\n"); #ifdef LAZY_SHARING_SETUP tassertMsg((useType == LAZY_INIT), "invalid useType %ld\n", (uval) useType); #else // FIXME: in the near future we should have SHARED objects registering // themselves also! tassertMsg(useType == NON_SHARED, "invalid useType %ld\n", (uval) useType); #endif // #ifdef LAZY_SHARING_SETUP SysStatus rc; ObjectHandle callbackOH; rc = CallBackUseType::Create(callBackUseTypeObjRef, (FileLinuxFileRef) getRef(), &destroyAckSync); tassertMsg(_SUCCESS(rc), "Create failed\n"); rc = DREF(callBackUseTypeObjRef)->giveAccessByServer(callbackOH, stub.getPid()); tassertMsg(_SUCCESS(rc), "giveAccess Failed\n"); if (_SUCCESS(rc)) { uval flen, offset; uval ut = useType; tassertMsg(stub.getOH().valid(), "stub not valid\n"); rc = stub._registerCallback(callbackOH, FileLinux::USETYPE_CALL_BACK, ut, flen, offset); tassertMsg(_SUCCESS(rc), "error register callback rc=(%ld,%ld,%ld)\n", _SERRCD(rc), _SCLSCD(rc), _SGENCD(rc)); passertMsg((ut == NON_SHARED || ut == SHARED), "ut %ld", (uval) ut); tassertMsg(flen != uval(~0), "flen %ld\n", flen); if (ut == SHARED) { tassertMsg(buffer == NULL, "?"); bufferInitData.fileLength = flen; // not setting up offset because it'll get from the server anyway? } else { #ifdef LAZY_SHARING_SETUP if (useType == NON_SHARED) { // actually this is not possible ... passertMsg(0, "impossible\n"); } else { tassertMsg(useType == LAZY_INIT, "was %ld\n", (uval) useType); tassertMsg(buffer == NULL, "?"); bufferInitData.initialOffset = offset; bufferInitData.fileLength = flen; } #else tassertMsg(buffer == NULL, "?"); bufferInitData.initialOffset = offset; bufferInitData.fileLength = flen; #endif // #ifdef LAZY_SHARING_SETUP } useType = (UseType) ut; } else { tassertMsg(0, "????"); } callBackUseTypeRegistered = 1; return rc; }
SysStatus execve_common(ProgExec::ArgDesc *argDesc) { // do loop with one iteration to allow break instead of goto on error ProgExec::ExecInfo newProg; FileLinuxRef flr = NULL; SysStatus rc; do { uval imageStart; ObjectHandle frOH; memset(&newProg, 0, sizeof(newProg)); // First, get filename's absolute path // FIXME: We need to unreference symlinks! PathNameDynamic<AllocGlobal> *pathName; uval pathLen, maxPathLen; char absfilename[128]; rc = FileLinux::GetAbsPath(argDesc->getFileName(), pathName, pathLen, maxPathLen); if (_FAILURE(rc)) break; rc = pathName->getUPath(pathLen, absfilename, 128); if (_FAILURE(rc)) break; rc = RunProcessOpen(absfilename, &imageStart, &frOH, &flr); if (_FAILURE(rc)) break; rc = ProgExec::ParseExecutable(imageStart, frOH, &newProg.prog); if (_FAILURE(rc)) { // Try it as a shell script // Looking for shell script will create the right // ArgDesc structure rc = shellInterp((char*)imageStart, PAGE_SIZE, argDesc); if (flr) { DREF(flr)->detach(); flr = NULL; } RunProcessClose(newProg.prog); if (_FAILURE(rc)) break; rc = RunProcessOpen(argDesc->getArgvPrefix()[0], &imageStart, &frOH, 0); if (_FAILURE(rc)) break; rc = ProgExec::ParseExecutable(imageStart, frOH, &argDesc->prog.prog); if (_FAILURE(rc)) break; } else { memcpy(&argDesc->prog, &newProg, sizeof(argDesc->prog)); } if (argDesc->prog.prog.interpOffset) { uval interpName = imageStart + argDesc->prog.prog.interpOffset; uval interpreterImageStart; rc = RunProcessOpen((const char*)interpName, &interpreterImageStart, &frOH, 0); // fixme cleanup needed if (_FAILURE(rc)) break; rc = ProgExec::ParseExecutable(interpreterImageStart, frOH, &argDesc->prog.interp); if (_FAILURE(rc)) break; } rc = ProgExec::ConfigStack(&argDesc->prog); if (_FAILURE(rc)) break; argDesc->prog.stackFR = argDesc->prog.localStackFR; // argv, envp are probably in memory that will be blown away. // Make a copy of that stuff here into memory that is safe. if (!KernelInfo::ControlFlagIsSet(KernelInfo::RUN_SILENT)) { uval i =0; char buf[1024]; char* next=buf; char** argv=argDesc->getArgv(); int len = 0; while (argv[i] && next< buf+510 && i<5) { len = strlen(argv[i]); if (len>16) len=16; if (len + next > buf+510) break; memcpy(next, argv[i], len); next+=len; *next = ' '; ++next; *next=0; ++i; } pid_t lpid; DREFGOBJ(TheProcessLinuxRef)->getpid(lpid); err_printf("Re-Mapping program %s (%s), k42 pid 0x%lx" " linux pid 0x%x.\n", absfilename, buf, DREFGOBJ(TheProcessRef)->getPID(), lpid); } if (traceUserEnabled()) { char llengths[1024]; char lengthstr[64]; char largv[1024]; uval largvlen, llengthlen, i, argvilen, lengthstrlen; char** argv=argDesc->getArgv(); largvlen = 0; llengthlen = 0; argvilen = 0; i = 0; largv[0] = '\0'; lengthstr[0] = '\0'; while (argv[i]) { argvilen = strlen(argv[i]); // +1 for space if ((argvilen + largvlen + 1) > 1024) break; baseSprintf(lengthstr, "%ld", argvilen); lengthstrlen = strlen(lengthstr); // +1 for space if ((lengthstrlen + llengthlen + 1) > 1024) break; // add spaces if not first thing if (i!=0) { strncpy(largv+largvlen, " ", 1); strncpy(llengths+llengthlen, " ", 1); llengthlen++; largvlen++; } strncpy(largv+largvlen, argv[i], argvilen); strncpy(llengths+llengthlen, lengthstr, lengthstrlen); llengthlen += lengthstrlen; largvlen += argvilen; i++; largv[largvlen] = '\0'; llengths[llengthlen] = '\0'; } TraceOSUserArgv(llengths, largv); } TraceOSUserStartExec(DREFGOBJ(TheProcessRef)->getPID(), (const char*)absfilename); ProgExec::UnMapAndExec(argDesc); passertMsg(0, "Shouldn't get here!!!\n") } while (0); if (flr) DREF(flr)->detach(); if (argDesc) { RunProcessClose(argDesc->prog.prog); RunProcessClose(argDesc->prog.interp); argDesc->destroy(); } else { RunProcessClose(newProg.prog); RunProcessClose(newProg.interp); } return rc; }