void GapStringBuffer::insert(const char *chars, size_t l)
{
	size_t gapPosInBuf = gapPos % bufferSize;
	if (l >= gapLen) { // we must ensure that gapLen is never 0, otherwise, we might end up with a NULL gapBuf pointer when moving the cursor to the end of the string
		// add first buf
		gc<Buffer *> buf = gcnew(Buffer);
		buf->prev = gapBuf;
		buf->next = gapBuf->next;
		memBarrier();
		gapBuf->next = buf;
		if (buf->next)
			buf->next->prev = buf;
		// copy chars if they were in the same buffer as the start of the gap
		size_t nextCharPos = gapPosInBuf + gapLen;
		if (nextCharPos < bufferSize)
			memcpy(buf->chars + nextCharPos, gapBuf->chars + nextCharPos, bufferSize - nextCharPos);
		// increase gapLen to reflect gap increasing
		gapLen += bufferSize;
		length += bufferSize;
		// now add additional buffers without copying, if required
		while (l >= gapLen) {
			buf = gcnew(Buffer);
			buf->prev = gapBuf;
			buf->next = gapBuf->next;
			memBarrier();
			gapBuf->next = buf;
			buf->next->prev = buf;
			gapLen += bufferSize;
			length += bufferSize;
		}
	}
	// now we have enough room, copy the characters
	while (l) {
		size_t w = bufferSize - gapPosInBuf;
		if (l >= w) {
			memcpy(gapBuf->chars + gapPosInBuf, chars, w);
			gapPosInBuf = 0;
			gapPos += w;
			gapLen -= w;
			gapBuf = gapBuf->next;
			l -= w;
			chars += w;
		}
		else {
			memcpy(gapBuf->chars + gapPosInBuf, chars, l);
			gapPosInBuf += l;
			gapPos += l;
			gapLen -= l;
			l = 0;
		}
	}
}
GapStringBuffer::GapStringBuffer(const String &string)
{
	size_t l = string.getLength();
	const char *chars = string.getChars();
	length = 0;
	first = NULL;
	gc<Buffer *> buf;
	Buffer *lastBuf = NULL;
	for (;;) {
		buf = gcnew(Buffer);
		buf->prev = lastBuf;
		buf->next = NULL;
		memBarrier();
		if (lastBuf)
			lastBuf->next = buf;
		if (!first)
			first = buf;
		lastBuf = buf;
		if (l < bufferSize) {
			memcpy(buf->chars, chars, l);
			gapBuf = buf;
			gapPos = length + l;
			gapLen = bufferSize - l;
			length += bufferSize;
			break;
		}
		else {
			memcpy(buf->chars, chars, bufferSize);
			l -= bufferSize;
			length += bufferSize;
		}
	}
}
void InterruptSource::trigger()
{
	if (!triggered) {
		triggered = true;
		memBarrier();
		if (enabled)
			dispatcher.notify();
	}
}
示例#4
0
/* Try to obatain space in proc to run th.  If th is NULL, an idle processor is signified */
void GC_GenConc(Proc_t *proc, Thread_t *th)
{
  int roundOffSize = minOffRequest;        /* Effective request size */
  int roundOnSize = minOnRequest;    
  int minorWorkToDo, majorWorkToDo;

  assert(proc->writelistCursor + 2 <= proc->writelistEnd);
  memBarrier();

  /* If space requirement satisfied and we are not turning collector off, do no work. */
  if (th != NULL) {
    assert(th->requestInfo != 0);
    if (th->requestInfo < 0) {
      if (GCStatus != GCPendingOff) {
	unsigned int writelistBytesAvailable = sizeof(val_t) * (proc->writelistEnd - proc->writelistCursor);
	assert((-th->requestInfo) <= writelistBytesAvailable);
	return;
      }
      roundOffSize = RoundUp(4, minOffRequest);
      roundOnSize = RoundUp(4, minOnRequest);
    }
    else {
      roundOffSize = RoundUp(th->requestInfo,minOffRequest);
      roundOnSize = RoundUp(th->requestInfo,minOnRequest);
    }
  }
  /* include 1.0 for the work done in replicating primary */
  minorWorkToDo = (int) ((GCStatus == GCAgressive ? 0.0 : 1.0) + CollectionRate) * roundOnSize;  
  majorWorkToDo = (int) ((GCStatus == GCAgressive ? 0.0 : 1.0) + CollectionRate) * roundOnSize;
  /* XXXXXXXXXXXXXX might fall behind XXXXXXXXX */
  if (roundOnSize > 2 * minOnRequest) {
    minorWorkToDo = (int) ((GCStatus == GCAgressive ? 0.0 : 1.0) + CollectionRate * (2 * minOnRequest));
    majorWorkToDo = (int) ((GCStatus == GCAgressive ? 0.0 : 1.0) + CollectionRate * (2 * minOnRequest));
  }

  /* If GCStatus is off but GCType is Major, then we immediately start a major collection */
  retry:
  switch (GCStatus) {
    case GCOff:                                          /* Off; Off, PendingOn */
      if (GC_GenConcHelp(th, proc,roundOffSize)) 
	goto satisfied;
      if (GCType == Major ? doAgressive : doMinorAgressive)
	goto pendingAgressive;
      goto pendingOn;
    case GCPendingAgressive:
    pendingAgressive:
      CollectorOn(proc);                               
      if (GC_GenConcHelp(th,proc,roundOnSize))
	goto satisfied;
      if (GCStatus == GCPendingOn)
	goto retry;
      goto fail;
    case GCPendingOn:
    pendingOn:
      if (GCType == Major ? doAgressive : doMinorAgressive) 
	CollectorTransition(proc);
      else
	CollectorOn(proc);
      if (multiPhase)
	goto retry;  
      if (GC_GenConcHelp(th, proc,roundOffSize)) 
	goto satisfied;
      if (GCStatus == GCPendingOff)
	goto retry;
      goto fail;
    case GCAgressive:
    case GCOn:
      do_work(proc, GCType == Minor ? minorWorkToDo : majorWorkToDo);
      if (multiPhase &&
	  reachMaxWork(proc) &&
	  GCStatus == GCPendingOff)
	goto retry;
      if (GC_GenConcHelp(th,proc,roundOnSize)) 
	goto satisfied;
      goto fail;
    case GCPendingOff:                                  /* If PendingOff, shared work is completed. */
      do_work(proc, INT_MAX);                            /* Actually bounded by the allocation of one processor */
      CollectorOff(proc);                               /* PendingOff; Off, PendingOn */
      goto retry;
    default: 
       DIE("GC_GenConc");
  }

 satisfied:
  return;

 fail:
  fprintf(stderr,"Proc %d: Collector behind.  Failed to allocate %d bytes for thread %ld\n", proc->procid, roundOnSize, th->tid);
  fprintf(stderr,"        GCType = %d.   GCStatus = %d.\n", GCType, GCStatus);
  DIE("out of memory");
}
示例#5
0
static void CollectorOff(Proc_t *proc)
{
  Thread_t *threadIterator = NULL;
  int isFirst;
  int nextGCType = Minor;      /* GCType will be written to during this function for the next GC
				  and so we save its value here for reading */
  procChangeState(proc, GCWork, 608);
  proc->segmentType |= FlipOff;

  if (collectDiag >= 2)
    printf("Proc %d: entered CollectorOff\n", proc->procid);
  assert(SetIsEmpty(&proc->work.objs));        /* Local stack must be empty */
  assert(GCStatus == GCPendingOff);
  memBarrier();

  PadCopyRange(&proc->copyRange);              /* Pad so that paranoid check works */

  isFirst = (weakBarrier(barriers,proc) == 0);
  if (isFirst) {
    ResetJob();
  }
  strongBarrier(barriers,proc);

  /* Local stacks must be empty. */
  assert(isLocalWorkEmpty(&proc->work));

  /* Replace all roots with replica */
  if (isFirst) 
    minor_global_scan(proc);   /* Even for a major GC since we already flipped global locs tenured when GC started */
  while ((threadIterator = NextJob()) != NULL) {
    complete_root_scan(proc, threadIterator);
    if (threadIterator->request == MajorGCRequestFromC) /* Runtime explicitly requests major GC */
      nextGCType = Major;
  }

  procChangeState(proc, GCWork, 611);
  proc->numRoot += SetLength(&proc->work.roots) + SetLength(&proc->work.globals);
  while (!SetIsEmpty(&proc->work.roots)) {
    ploc_t root = (ploc_t) SetPop(&proc->work.roots);
    flipRootLoc(GCType, root);
  }
  while (!SetIsEmpty(&proc->work.globals)) {
    ptr_t global = SetPop(&proc->work.globals);
    ploc_t replicaLoc = DupGlobal(global);
    flipRootLoc(GCType, replicaLoc);
  }
  FetchAndAdd(&totalReplicated, proc->segUsage.bytesReplicated + proc->cycleUsage.bytesReplicated);
  strongBarrier(barriers,proc);

  /* Only the designated thread needs to perform the following */
  if (isFirst) {
    if (GCType == Minor) {
      double liveRatio = 0.0;
      int i, copied = 0;
      paranoid_check_all(nursery, fromSpace, fromSpace, NULL, largeSpace);
      minor_global_promote(proc);
      for (i=0; i<NumProc; i++) {
	Proc_t *p = getNthProc(i);;
	copied += bytesCopied(&p->cycleUsage) + bytesCopied(&p->segUsage);
      }
      liveRatio = (double) (copied) / (double) Heap_GetUsed(nursery);
      add_statistic(&minorSurvivalStatistic, liveRatio);
    }
    else { /* Major */
      discardNextSharedStack(workStack); /* Discard nextBackObj/nextBackLocs on major GC */
      paranoid_check_all(nursery, fromSpace, toSpace, NULL, largeSpace);
      gc_large_endCollect();
      HeapAdjust2(totalRequest, totalUnused, totalReplicated,  
		  CollectionRate, doAgressive ? 2 : 1,
		  nursery, fromSpace, toSpace);
      reducedTenuredSize = Heap_GetSize(toSpace);
      expandedTenuredSize = reducedToExpanded(reducedTenuredSize, CollectionRate, doAgressive ? 2 : 1);
      Heap_Resize(fromSpace, 0, 1);
      typed_swap(Heap_t *, fromSpace, toSpace);
      NumMajorGC++;                          
    }
    typed_swap(int, primaryGlobalOffset, replicaGlobalOffset);
    typed_swap(int, primaryArrayOffset, replicaArrayOffset);
    typed_swap(int, primaryStackletOffset, replicaStackletOffset);
    Heap_Resize(nursery,reducedNurserySize,1);
    NumGC++;
    GCStatus = GCOff;
    if (Heap_GetAvail(fromSpace) < tenuredReserve + Heap_GetSize(nursery)) {
      /*  The next GC needs to be a major GC so we must begin allocation in the fromSpace immediately. 
	  We permit allocation to continue so we don't flip on again too soon.  However, allocation
	  is restricted so the major collection is started soon so that an accurate survival rate
	  can be computed. */
      GCType = Major;        
      fromSpace->top = fromSpace->cursor + (minOffRequest * NumProc) / sizeof(val_t);
    }
    else
      GCType = nextGCType;
  }

  /* All system threads need to reset their limit pointer */
  ResetAllocation(proc, NULL);
  proc->writelistCursor = proc->writelistStart;

  strongBarrier(barriers,proc);
  establishCopyRange(proc);    /* Called here to copyRanges are initialized for use in GCRelease */

  if (collectDiag >= 2)
    printf("Proc %d: leaving CollectorOff\n", proc->procid);
}