On Sunday, 6 July 2014 at 04:58:42 UTC, Brian Schott wrote:

So something like this would work?

void* GCAwareRealloc(void* ptr, size_t size)
{
  import core.thread;
  void* r;
  thread_enterCriticalRegion();
  scope (exit) thread_exitCriticalRegion();
  r = realloc(ptr, size);
  // Assuming that addRange performs an update of size
  GC.addRange(r, size);
  return r;
}

No, it can cause a deadlock:

Thread 1: thread_enterCriticalRegion();
Thread 2: Takes GC lock.
Thread 1: Tries to take GC lock to add range, but it has to wait.
Thread 2: triggers a collection -> thread_suspendAll().

Thread 2 waits on thread 1 to exit critical section, thread 1 waits on thread 2 to release GC lock.

So the best we can do at the moment is:
void* GCAwareRealloc(void* ptr, size_t size)
{
  void* r;
  GC.disable;
  scope (exit) GC.enable;
  GC.removeRange(ptr);
  r = realloc(ptr, size);
  GC.addRange(r, size);
  return r;
}

With your proposed enhancement we get:
void* GCAwareRealloc(void* ptr, size_t size)
{
  void* r;
  GC.disable;
  scope (exit) GC.enable;
  r = realloc(ptr, size);
  if (r != ptr)
    GC.removeRange(ptr);
  GC.addRange(r, size); // if r == ptr, only updates size
  return r;
}

Which executes a little faster because we sometimes do 1 less GC range operation (plus 1 less GC lock.)

Reply via email to