Exemple #1
0
void * NONNULL(1) MALLOC
mm_private_space_xalloc(struct mm_private_space *space, size_t size)
{
    void *ptr = mm_private_space_alloc(space, size);
    if (unlikely(ptr == NULL))
        mm_fatal(errno, "error allocating %zu bytes of memory", size);
    return ptr;
}
Exemple #2
0
void * NONNULL(1) MALLOC
mm_shared_space_xcalloc(struct mm_shared_space *space, size_t count, size_t size)
{
    void *ptr = mm_shared_space_calloc(space, count, size);
    if (unlikely(ptr == NULL))
        mm_fatal(errno, "error allocating %zu bytes of memory", size);
    return ptr;
}
Exemple #3
0
static mm_mspace_t
mm_mspace_create(void)
{
    mm_mspace_t space;
    space.opaque = create_mspace(0, 0);
    if (space.opaque == NULL)
        mm_fatal(errno, "failed to create mspace");
    return space;
}
Exemple #4
0
mm_event_kqueue_prepare(struct mm_event_kqueue *event_backend)
{
	ENTER();

	// Open a kqueue file descriptor.
	event_backend->event_fd = kqueue();
	if (event_backend->event_fd == -1)
		mm_fatal(errno, "Failed to create kqueue");

	LEAVE();
}
Exemple #5
0
mm_event_batch_expand(struct mm_event_batch *batch)
{
	ENTER();

	if (unlikely(batch->nchanges_max == MM_EVENT_NCHANGES_MAX))
		mm_fatal(0, "too many event change entries");

	batch->nchanges_max *= 2;
	batch->changes = mm_common_realloc(batch->changes,
					   batch->nchanges_max * sizeof(struct mm_event_change));

	LEAVE();
}
Exemple #6
0
uint16_t
mm_topology_getncpus(void)
{
#if ENABLE_SMP
# if defined(HAVE_SYS_SYSCTL_H) && defined(HW_AVAILCPU)
//#  define SELECTOR "hw.ncpu"
#  define SELECTOR "hw.activecpu"
//#  define SELECTOR "hw.physicalcpu"
	int num;
	size_t len = sizeof num;
	if (sysctlbyname(SELECTOR, &num, &len, NULL, 0) < 0)
		mm_fatal(errno, "Failed to count cores.");
	return num;
# elif defined(_SC_NPROCESSORS_ONLN)
	int nproc_onln = sysconf(_SC_NPROCESSORS_ONLN);
	if (nproc_onln < 0)
		mm_fatal(errno, "Failed to count cores.");
	return nproc_onln;
# else
#  error "Unsupported SMP architecture."
# endif
#endif
	return MM_DEFAULT_NCPUS;
}
Exemple #7
0
mm_chunk_enqueue_deferred(struct mm_thread *thread, bool flush)
{
	if (!flush && thread->deferred_chunks_count < MM_CHUNK_FLUSH_THRESHOLD)
		return;

	// Capture all the deferred chunks.
	struct mm_stack chunks = thread->deferred_chunks;
	mm_stack_prepare(&thread->deferred_chunks);
	thread->deferred_chunks_count = 0;

	// Try to submit the chunks to respective reclamation queues.
	while (!mm_stack_empty(&chunks)) {
		struct mm_chunk *chunk = mm_chunk_stack_remove(&chunks);

		struct mm_domain *domain = mm_regular_domain;
#if ENABLE_SMP
		mm_chunk_t tag = mm_chunk_gettag(chunk);
		struct mm_thread *origin = mm_domain_getthread(domain, tag);
#else
		struct mm_thread *origin = mm_domain_getthread(domain, 0);
#endif
		uint32_t backoff = 0;
		while (!mm_thread_trypost_1(origin, mm_chunk_free_req, (uintptr_t) chunk)) {
			if (backoff >= MM_BACKOFF_SMALL) {
				// If failed to submit the chunk after a number
				// of attempts then defer it again.
				mm_chunk_stack_insert(&thread->deferred_chunks, chunk);
				thread->deferred_chunks_count++;
				break;
			}
			backoff = mm_thread_backoff(backoff);
		}
	}

	// Let know if chunk reclamation consistently has problems.
	if (thread->deferred_chunks_count > MM_CHUNK_ERROR_THRESHOLD) {
		if (thread->deferred_chunks_count < MM_CHUNK_FATAL_THRESHOLD)
			mm_error(0, "Problem with chunk reclamation");
		else
			mm_fatal(0, "Problem with chunk reclamation");
	}
}
Exemple #8
0
static void
mm_pool_grow(struct mm_pool *pool)
{
	ENTER();

	// Check for 32-bit integer overflow.
	uint32_t total_capacity = pool->block_capacity * pool->block_array_used;
	if (unlikely(total_capacity > (total_capacity + pool->block_capacity)))
		mm_fatal(0, "the '%s' memory pool overflow", pool->pool_name);

	// If needed grow the block container array.
	if (pool->block_array_used == pool->block_array_size) {
		if (pool->block_array_size)
			pool->block_array_size *= 2;
		else
			pool->block_array_size = 4;

		pool->block_array = mm_arena_realloc(
			pool->arena,
			pool->block_array,
			pool->block_array_size * sizeof(char *));
	}

	// Allocate a new memory block.
	char *block = mm_arena_alloc(pool->arena, MM_POOL_BLOCK_SIZE);
	pool->block_array[pool->block_array_used] = block;
	pool->block_array_used++;

	pool->block_cur_ptr = block;
	pool->block_end_ptr = block + pool->block_capacity * pool->item_size;

	mm_verbose("grow the '%s' memory pool to %u elements, occupy %lu bytes",
		   pool->pool_name,
		   pool->block_capacity * pool->block_array_used,
		   (unsigned long) MM_POOL_BLOCK_SIZE * pool->block_array_used);

	LEAVE();
}
Exemple #9
0
mm_event_listener_prepare(struct mm_event_listener *listener, struct mm_event_dispatch *dispatch,
			  struct mm_thread *thread)
{
	ENTER();

#if ENABLE_NOTIFY_STAMP
	listener->state = 0;
#else
	listener->listen_stamp = 0;
	listener->notify_stamp = 0;
#endif

	listener->thread = thread;
	listener->busywait = 0;
	listener->nwaiters = 0;

#if ENABLE_LINUX_FUTEX
	// Nothing to do for futexes.
#elif ENABLE_MACH_SEMAPHORE
	kern_return_t r = semaphore_create(mach_task_self(), &listener->semaphore,
					   SYNC_POLICY_FIFO, 0);
	if (r != KERN_SUCCESS)
		mm_fatal(0, "semaphore_create");
#else
	mm_thread_monitor_prepare(&listener->monitor);
#endif

	// Initialize the receiver.
	mm_thread_t thread_number = listener - dispatch->listeners;
	mm_event_receiver_prepare(&listener->receiver, dispatch, thread_number);

	// Initialize change event storage.
	mm_event_batch_prepare(&listener->changes, 256);

	LEAVE();
}
Exemple #10
0
void fatal (char *string)
{
  mm_fatal (string);		/* pass up the string */
  abort ();			/* die horribly */
}
Exemple #11
0
static long master (MAILSTREAM *stream,append_t af,void *data)
{
  MAILSTREAM *st;
  MAILSTATUS status;
  STRING *message;
  FILE *pi,*po;
  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
  long ret = NIL;
  unsigned long i,j;
  int c,pid,pipei[2],pipeo[2];
  char *s,*t,tmp[MAILTMPLEN];
  lockproxycopy = NIL;		/* not doing a lock proxycopy */
				/* make pipe from slave */
  if (pipe (pipei) < 0) mm_log ("Can't create input pipe",ERROR);
  else if (pipe (pipeo) < 0) {
    mm_log ("Can't create output pipe",ERROR);
    close (pipei[0]); close (pipei[1]);
  }
  else if ((pid = fork ()) < 0) {/* make slave */
    mm_log ("Can't create execution process",ERROR);
    close (pipei[0]); close (pipei[1]);
    close (pipeo[0]); close (pipeo[1]);
  }
  else if (lockslavep = !pid) {	/* are we slave or master? */
    alarm (0);			/* slave doesn't have alarms or signals */
    for (c = 0; c < NSIG; c++) signal (c,SIG_DFL);
    if (!(slavein = fdopen (pipeo[0],"r")) ||
	!(slaveout = fdopen (pipei[1],"w")))
      fatal ("Can't do slave pipe buffered I/O");
    close (pipei[0]);		/* close parent's side of the pipes */
    close (pipeo[1]);
  }

  else {			/* master process */
    void *blockdata = (*bn) (BLOCK_SENSITIVE,NIL);
    close (pipei[1]);		/* close slave's side of the pipes */
    close (pipeo[0]);
    if (!(pi = fdopen (pipei[0],"r")) || !(po = fdopen (pipeo[1],"w")))
      fatal ("Can't do master pipe buffered I/O");
				/* do slave events until EOF */
				/* read event */
    while (fgets (tmp,MAILTMPLEN,pi)) {
				/* tie off event at end of line */
      if (s = strchr (tmp,'\n')) *s = '\0';
      else {
	s = "Execution process event string too long: ";
	sprintf (t = (char *) fs_get (strlen (s) + strlen (tmp) + 1),"%s:%s",
		 s,tmp);
	fatal (t);
      }
      switch (tmp[0]) {		/* analyze event */
      case 'A':			/* append callback */
	if ((*af) (NIL,data,&s,&t,&message)) {
	  if (i = message ? SIZE (message) : 0) {
	    if (!s) s = "";	/* default values */
	    if (!t) t = "";
	  }
	  else s = t = "";	/* no flags or date if no message */
	  errno = NIL;		/* reset last error */
				/* build response */
	  sprintf (tmp,"+%lu %s%lu %s%lu ",strlen (s),s,strlen (t),t,i);
	  if (fputs (tmp,po) == EOF) {
	    sprintf (tmp,"Failed to pipe command \"+%lu %s%lu %s%lu \": %s",
		     strlen (s),s,strlen (t),t,i,strerror (errno));
	    fatal (tmp);
	  }
				/* write message text */
	  if (i) do if (putc (c = 0xff & SNX (message),po) == EOF) {
	    sprintf (tmp,"Failed to pipe %lu bytes (of %lu), last=%u: %s",
		     i,message->size,c,strerror (errno));
	    fatal (tmp);
	  } while (--i);
	}
	else putc ('-',po);	/* append error */
	fflush (po);
	break;
      case '&':			/* slave wants a proxycopy? */
	lockproxycopy = T;
	break;

      case 'L':			/* mm_log() */
	i = strtoul (tmp+1,&s,10);
	if (!s || (*s++ != ' ')) {
	  s = "Invalid log event arguments: ";
	  sprintf (t = (char *) fs_get (strlen (s) + strlen (tmp) + 1),"%s:%s",
		   s,tmp);
	  fatal (t);
	}
	mm_log (s,i);
	break;
      case 'N':			/* mm_notify() */
	st = (MAILSTREAM *) strtoul (tmp+1,&s,16);
	if (s && (*s++ == ' ')) {
	  i = strtoul (s,&s,10);/* get severity */
	  if (s && (*s++ == ' ')) {
	    mm_notify ((st == stream) ? stream : NIL,s,i);
	    break;
	  }
	}
	s = "Invalid notify event arguments: ";
	sprintf (t = (char *) fs_get (strlen (s) + strlen (tmp) + 1),"%s:%s",
		 s,tmp);
	fatal (t);

      case 'S':			/* mm_status() */
	st = (MAILSTREAM *) strtoul (tmp+1,&s,16);
	if (s && (*s++ == ' ')) {
	  status.flags = strtoul (s,&s,10);
	  if (s && (*s++ == ' ')) {
	    status.messages = strtoul (s,&s,10);
	    if (s && (*s++ == ' ')) {
	      status.recent = strtoul (s,&s,10);
	      if (s && (*s++ == ' ')) {
		status.unseen = strtoul (s,&s,10);
		if (s && (*s++ == ' ')) {
		  status.uidnext = strtoul (s,&s,10);
		  if (s && (*s++ == ' ')) {
		    status.uidvalidity = strtoul (s,&s,10);
		    if (s && (*s++ == ' ')) {
		      mm_status ((st == stream) ? stream : NIL,s,&status);
		      break;
		    }
		  }
		}
	      }
	    }
	  }
	}
	s = "Invalid status event arguments: ";
	sprintf (t = (char *) fs_get (strlen (s) + strlen (tmp) + 1),"%s:%s",
		 s,tmp);
	fatal (t);
      case 'C':			/* mm_critical() */
	st = (MAILSTREAM *) strtoul (tmp+1,&s,16);
	mm_critical ((st == stream) ? stream : NIL);
	break;
      case 'X':			/* mm_nocritical() */
	st = (MAILSTREAM *) strtoul (tmp+1,&s,16);
	mm_nocritical ((st == stream) ? stream : NIL);
	break;

      case 'D':			/* mm_diskerror() */
	st = (MAILSTREAM *) strtoul (tmp+1,&s,16);
	if (s && (*s++ == ' ')) {
	  i = strtoul (s,&s,10);
	  if (s && (*s++ == ' ')) {
	    j = (long) strtoul (s,NIL,10);
	    if (st == stream)	/* let's hope it's on usable stream */
	      putc (mm_diskerror (stream,(long) i,j) ? '+' : '-',po);
	    else if (j) {	/* serious diskerror on slave-created stream */
	      mm_log ("Retrying disk write to avoid mailbox corruption!",WARN);
	      sleep (5);	/* give some time for it to clear up */
	      putc ('-',po);	/* don't abort */
	    }
	    else {		/* recoverable on slave-created stream */
	      mm_log ("Error on disk write",ERROR);
	      putc ('+',po);	/* so abort it */
	    }
	    fflush (po);	/* force it out either way */
	    break;
	  }
	}
	s = "Invalid diskerror event arguments: ";
	sprintf (t = (char *) fs_get (strlen (s) + strlen (tmp) + 1),"%s:%s",
		 s,tmp);
	fatal (t);
      case 'F':			/* mm_fatal() */
	mm_fatal (tmp+1);
	break;
      default:			/* random lossage */
	s = "Unknown event from execution process: ";
	sprintf (t = (char *) fs_get (strlen (s) + strlen (tmp) + 1),"%s:%s",
		 s,tmp);
	fatal (t);
      }
    }
    fclose (pi); fclose (po);	/* done with the pipes */
				/* get slave status */
    grim_pid_reap_status (pid,NIL,&ret);
    if (ret & 0177) {		/* signal or stopped */
      sprintf (tmp,"Execution process terminated abnormally (%lx)",ret);
      mm_log (tmp,ERROR);
      ret = NIL;
    }
    else ret >>= 8;		/* return exit code */
    (*bn) (BLOCK_NONSENSITIVE,blockdata);
  }
  return ret;			/* return status */
}