void __malloc_fork_unlock_child (void) { if (__malloc_initialized < 1) return; /* Push all arenas to the free list, except thread_arena, which is attached to the current thread. */ __libc_lock_init (free_list_lock); if (thread_arena != NULL) thread_arena->attached_threads = 1; free_list = NULL; for (mstate ar_ptr = &main_arena;; ) { __libc_lock_init (ar_ptr->mutex); if (ar_ptr != thread_arena) { /* This arena is no longer attached to any thread. */ ar_ptr->attached_threads = 0; ar_ptr->next_free = free_list; free_list = ar_ptr; } ar_ptr = ar_ptr->next; if (ar_ptr == &main_arena) break; } __libc_lock_init (list_lock); }
/* Open a directory stream on a file descriptor in Hurd internal form. We do no checking here on the descriptor. */ DIR * _hurd_fd_opendir (struct hurd_fd *d) { DIR *dirp; if (d == NULL) { errno = EBADF; return NULL; } dirp = (DIR *) malloc (sizeof (DIR)); if (dirp == NULL) return NULL; /* Set the descriptor to close on exec. */ HURD_CRITICAL_BEGIN; __spin_lock (&d->port.lock); d->flags |= FD_CLOEXEC; __spin_unlock (&d->port.lock); HURD_CRITICAL_END; dirp->__fd = d; dirp->__data = dirp->__ptr = NULL; dirp->__entry_data = dirp->__entry_ptr = 0; dirp->__allocation = 0; dirp->__size = 0; __libc_lock_init (dirp->__lock); return dirp; }
internal_function __alloc_dir (int fd, bool close_fd, const struct stat64 *statp) { /* We always have to set the close-on-exit flag if the user provided the file descriptor. Otherwise only if we have no working O_CLOEXEC support. */ #ifdef O_CLOEXEC if (! close_fd || ! check_have_o_cloexec (fd)) #endif { if (__builtin_expect (__fcntl (fd, F_SETFD, FD_CLOEXEC), 0) < 0) goto lose; } const size_t default_allocation = (BUFSIZ < sizeof (struct dirent64) ? sizeof (struct dirent64) : BUFSIZ); size_t allocation; #ifdef _STATBUF_ST_BLKSIZE if (__builtin_expect ((size_t) statp->st_blksize >= sizeof (struct dirent64), 1)) allocation = statp->st_blksize; else #endif allocation = default_allocation; DIR *dirp = (DIR *) malloc (sizeof (DIR) + allocation); if (dirp == NULL) { #ifdef _STATBUF_ST_BLKSIZE if (allocation == statp->st_blksize && allocation != default_allocation) { allocation = default_allocation; dirp = (DIR *) malloc (sizeof (DIR) + allocation); } if (dirp == NULL) #endif lose: { if (close_fd) { int save_errno = errno; close_not_cancel_no_status (fd); __set_errno (save_errno); } return NULL; } } dirp->fd = fd; #ifndef NOT_IN_libc __libc_lock_init (dirp->lock); #endif dirp->allocation = allocation; dirp->size = 0; dirp->offset = 0; dirp->filepos = 0; return dirp; }
/* Open a directory stream on NAME. */ DIR * __opendir (const char *name) { DIR *dirp; int fd; struct hurd_fd *d; if (name[0] == '\0') { /* POSIX.1-1990 says an empty name gets ENOENT; but `open' might like it fine. */ __set_errno (ENOENT); return NULL; } { /* Append trailing slash to directory name to force ENOTDIR if it's not a directory. */ size_t len = strlen (name); if (name[len - 1] == '/') fd = __open (name, O_RDONLY); else { char n[len + 2]; memcpy (n, name, len); n[len] = '/'; n[len + 1] = '\0'; fd = __open (n, O_RDONLY); } } if (fd < 0) return NULL; dirp = (DIR *) malloc (sizeof (DIR)); if (dirp == NULL) { __close (fd); return NULL; } /* Extract the pointer to the descriptor structure. */ __mutex_lock (&_hurd_dtable_lock); d = dirp->__fd = _hurd_dtable[fd]; __mutex_unlock (&_hurd_dtable_lock); /* Set the descriptor to close on exec. */ __spin_lock (&d->port.lock); d->flags |= FD_CLOEXEC; __spin_unlock (&d->port.lock); dirp->__data = dirp->__ptr = NULL; dirp->__entry_data = dirp->__entry_ptr = 0; dirp->__allocation = 0; dirp->__size = 0; __libc_lock_init (dirp->__lock); return dirp; }
internal_function __alloc_dir (int fd, bool close_fd, int flags, const struct stat64 *statp) { /* We always have to set the close-on-exit flag if the user provided the file descriptor. Otherwise only if we have no working O_CLOEXEC support. */ #ifdef O_CLOEXEC if ((! close_fd && (flags & O_CLOEXEC) == 0) || ! check_have_o_cloexec (fd)) #endif { if (__builtin_expect (__fcntl (fd, F_SETFD, FD_CLOEXEC), 0) < 0) goto lose; } const size_t default_allocation = (4 * BUFSIZ < sizeof (struct dirent64) ? sizeof (struct dirent64) : 4 * BUFSIZ); const size_t small_allocation = (BUFSIZ < sizeof (struct dirent64) ? sizeof (struct dirent64) : BUFSIZ); size_t allocation = default_allocation; #ifdef _STATBUF_ST_BLKSIZE /* Increase allocation if requested, but not if the value appears to be bogus. */ if (statp != NULL) allocation = MIN (MAX ((size_t) statp->st_blksize, default_allocation), MAX_DIR_BUFFER_SIZE); #endif DIR *dirp = (DIR *) malloc (sizeof (DIR) + allocation); if (dirp == NULL) { allocation = small_allocation; dirp = (DIR *) malloc (sizeof (DIR) + allocation); if (dirp == NULL) lose: { if (close_fd) { int save_errno = errno; close_not_cancel_no_status (fd); __set_errno (save_errno); } return NULL; } } dirp->fd = fd; #if IS_IN (libc) __libc_lock_init (dirp->lock); #endif dirp->allocation = allocation; dirp->size = 0; dirp->offset = 0; dirp->filepos = 0; dirp->errcode = 0; return dirp; }
static pid_t __fork(void) { pid_t pid; struct handler_list * prepare, * child, * parent; __pthread_mutex_lock(&pthread_atfork_lock); prepare = pthread_atfork_prepare; child = pthread_atfork_child; parent = pthread_atfork_parent; pthread_call_handlers(prepare); __pthread_once_fork_prepare(); #ifdef __MALLOC__ __pthread_mutex_lock(&__malloc_sbrk_lock); __pthread_mutex_lock(&__malloc_heap_lock); #ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__ __pthread_mutex_lock(&__malloc_mmb_heap_lock); #endif #elif defined(__MALLOC_STANDARD__) || defined(__MALLOC_SIMPLE__) __pthread_mutex_lock(&__malloc_lock); #endif pid = __libc_fork(); if (pid == 0) { #if defined(__MALLOC_STANDARD__) || defined(__MALLOC_SIMPLE__) __libc_lock_init_recursive(__malloc_lock); #elif defined(__MALLOC__) #ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__ __libc_lock_init_adaptive(__malloc_mmb_heap_lock); #endif __libc_lock_init_adaptive(__malloc_heap_lock); __libc_lock_init(__malloc_sbrk_lock); #endif __libc_lock_init_adaptive(pthread_atfork_lock); __pthread_reset_main_thread(); __fresetlockfiles(); __pthread_once_fork_child(); pthread_call_handlers(child); } else { #if defined(__MALLOC_STANDARD__) || defined(__MALLOC_SIMPLE__) __pthread_mutex_unlock(&__malloc_lock); #elif defined(__MALLOC__) #ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__ __pthread_mutex_unlock(&__malloc_mmb_heap_lock); #endif __pthread_mutex_unlock(&__malloc_heap_lock); __pthread_mutex_unlock(&__malloc_sbrk_lock); #endif __pthread_mutex_unlock(&pthread_atfork_lock); __pthread_once_fork_parent(); pthread_call_handlers(parent); } return pid; }
internal_function __alloc_dir (int fd, bool close_fd, const struct stat64 *statp) { if (__builtin_expect (__fcntl (fd, F_SETFD, FD_CLOEXEC), 0) < 0) goto lose; size_t allocation; #ifdef _STATBUF_ST_BLKSIZE if (__builtin_expect ((size_t) statp->st_blksize >= sizeof (struct dirent64), 1)) allocation = statp->st_blksize; else #endif allocation = (BUFSIZ < sizeof (struct dirent64) ? sizeof (struct dirent64) : BUFSIZ); const int pad = -sizeof (DIR) % __alignof__ (struct dirent64); DIR *dirp = (DIR *) malloc (sizeof (DIR) + allocation + pad); if (dirp == NULL) lose: { if (close_fd) { int save_errno = errno; close_not_cancel_no_status (fd); __set_errno (save_errno); } return NULL; } memset (dirp, '\0', sizeof (DIR)); dirp->data = (char *) (dirp + 1) + pad; dirp->allocation = allocation; dirp->fd = fd; __libc_lock_init (dirp->lock); return dirp; }
/* Open a directory stream on NAME. */ DIR * __opendir (const char *name) { DIR *dirp; int fd; struct hurd_fd *d; fd = __open (name, O_RDONLY); if (fd < 0) return NULL; dirp = (DIR *) malloc (sizeof (DIR)); if (dirp == NULL) { __close (fd); return NULL; } /* Extract the pointer to the descriptor structure. */ __mutex_lock (&_hurd_dtable_lock); d = dirp->__fd = _hurd_dtable[fd]; __mutex_unlock (&_hurd_dtable_lock); /* Set the descriptor to close on exec. */ __spin_lock (&d->port.lock); d->flags |= FD_CLOEXEC; __spin_unlock (&d->port.lock); dirp->__data = dirp->__ptr = NULL; dirp->__entry_data = dirp->__entry_ptr = 0; dirp->__allocation = 0; dirp->__size = 0; __libc_lock_init (dirp->__lock); return dirp; }
/* Open a directory stream on NAME. */ DIR * __opendir (const char *name) { DIR *dirp; struct stat64 statbuf; int fd; size_t allocation; int save_errno; if (__builtin_expect (name[0], '\1') == '\0') { /* POSIX.1-1990 says an empty name gets ENOENT; but `open' might like it fine. */ __set_errno (ENOENT); return NULL; } #ifdef O_DIRECTORY /* Test whether O_DIRECTORY works. */ if (o_directory_works == 0) tryopen_o_directory (); /* We can skip the expensive `stat' call if O_DIRECTORY works. */ if (o_directory_works < 0) #endif { /* We first have to check whether the name is for a directory. We cannot do this after the open() call since the open/close operation performed on, say, a tape device might have undesirable effects. */ if (__builtin_expect (__xstat64 (_STAT_VER, name, &statbuf), 0) < 0) return NULL; if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { __set_errno (ENOTDIR); return NULL; } } fd = open_not_cancel_2 (name, O_RDONLY|O_NDELAY|EXTRA_FLAGS|O_LARGEFILE); if (__builtin_expect (fd, 0) < 0) return NULL; /* Now make sure this really is a directory and nothing changed since the `stat' call. We do not have to perform the test for the descriptor being associated with a directory if we know the O_DIRECTORY flag is honored by the kernel. */ if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &statbuf), 0) < 0) goto lose; #ifdef O_DIRECTORY if (o_directory_works <= 0) #endif { if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { save_errno = ENOTDIR; goto lose; } } if (__builtin_expect (__fcntl (fd, F_SETFD, FD_CLOEXEC), 0) < 0) goto lose; #ifdef _STATBUF_ST_BLKSIZE if (__builtin_expect ((size_t) statbuf.st_blksize >= sizeof (struct dirent64), 1)) allocation = statbuf.st_blksize; else #endif allocation = (BUFSIZ < sizeof (struct dirent64) ? sizeof (struct dirent64) : BUFSIZ); const int pad = -sizeof (DIR) % __alignof__ (struct dirent64); dirp = (DIR *) malloc (sizeof (DIR) + allocation + pad); if (dirp == NULL) lose: { save_errno = errno; close_not_cancel_no_status (fd); __set_errno (save_errno); return NULL; } memset (dirp, '\0', sizeof (DIR)); dirp->data = (char *) (dirp + 1) + pad; dirp->allocation = allocation; dirp->fd = fd; __libc_lock_init (dirp->lock); return dirp; }
static mstate _int_new_arena (size_t size) { mstate a; heap_info *h; char *ptr; unsigned long misalign; h = new_heap (size + (sizeof (*h) + sizeof (*a) + MALLOC_ALIGNMENT), mp_.top_pad); if (!h) { /* Maybe size is too large to fit in a single heap. So, just try to create a minimally-sized arena and let _int_malloc() attempt to deal with the large request via mmap_chunk(). */ h = new_heap (sizeof (*h) + sizeof (*a) + MALLOC_ALIGNMENT, mp_.top_pad); if (!h) return 0; } a = h->ar_ptr = (mstate) (h + 1); malloc_init_state (a); a->attached_threads = 1; /*a->next = NULL;*/ a->system_mem = a->max_system_mem = h->size; /* Set up the top chunk, with proper alignment. */ ptr = (char *) (a + 1); misalign = (unsigned long) chunk2mem (ptr) & MALLOC_ALIGN_MASK; if (misalign > 0) ptr += MALLOC_ALIGNMENT - misalign; top (a) = (mchunkptr) ptr; set_head (top (a), (((char *) h + h->size) - ptr) | PREV_INUSE); LIBC_PROBE (memory_arena_new, 2, a, size); mstate replaced_arena = thread_arena; thread_arena = a; __libc_lock_init (a->mutex); __libc_lock_lock (list_lock); /* Add the new arena to the global list. */ a->next = main_arena.next; /* FIXME: The barrier is an attempt to synchronize with read access in reused_arena, which does not acquire list_lock while traversing the list. */ atomic_write_barrier (); main_arena.next = a; __libc_lock_unlock (list_lock); __libc_lock_lock (free_list_lock); detach_arena (replaced_arena); __libc_lock_unlock (free_list_lock); /* Lock this arena. NB: Another thread may have been attached to this arena because the arena is now accessible from the main_arena.next list and could have been picked by reused_arena. This can only happen for the last arena created (before the arena limit is reached). At this point, some arena has to be attached to two threads. We could acquire the arena lock before list_lock to make it less likely that reused_arena picks this new arena, but this could result in a deadlock with __malloc_fork_lock_parent. */ __libc_lock_lock (a->mutex); return a; }