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; }
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; }
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; }
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(); }
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(); }
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; }
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"); } }
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(); }
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(); }
void fatal (char *string) { mm_fatal (string); /* pass up the string */ abort (); /* die horribly */ }
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 */ }