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;
}
Esempio n. 2
0
/* 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;
}
Esempio n. 3
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;
}
Esempio n. 4
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;
}
Esempio n. 5
0
/* 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;
}
Esempio n. 6
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;
}
Esempio n. 7
0
/* 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;
}
Esempio n. 8
0
/* virtual */ SysStatusProcessID
RegionReplicated::getPID()
{
    return DREF(COGLOBAL(proc))->getPID();
}
Esempio n. 9
0
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;
}
Esempio n. 10
0
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);
}
Esempio n. 11
0
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;
}
Esempio n. 12
0
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;
}
Esempio n. 13
0
File: FD.C Progetto: BillTheBest/k42
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;
}
Esempio n. 14
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;
}
Esempio n. 15
0
File: smtTest.C Progetto: jimix/k42
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 {
Esempio n. 16
0
/* 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;
}
Esempio n. 17
0
// 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");
}
Esempio n. 18
0
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;
}
Esempio n. 19
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;
}
Esempio n. 20
0
/*
 * 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;
}
Esempio n. 21
0
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;
}
Esempio n. 22
0
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;
}
Esempio n. 23
0
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;
}
Esempio n. 24
0
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;

}
Esempio n. 25
0
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;
}