0N/A# The contents of this file are subject to the terms of the
0N/A# Common Development and Distribution License (the "License").
0N/A# You may not use this file except in compliance with the License.
0N/A# See the License for the specific language governing permissions
0N/A# and limitations under the License.
0N/A# When distributing Covered Code, include this CDDL HEADER in each
0N/A# If applicable, add the following below this CDDL HEADER, with the
0N/A# fields enclosed by brackets "[]" replaced with your own identifying
0N/A# information: Portions Copyright [yyyy] [name of copyright owner]
0N/A# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
0N/A# Use is subject to license terms.
0N/AThe Solaris Process Model Unification project:
0N/A PSARC/2002/117 Solaris Process Model Unification
0N/A 4470917 Solaris Process Model Unification
0N/Afolded libthread into libc and has led to some fundamental changes
0N/Ain the rules by which code in libc must be developed and maintained.
0N/AAll code in libc must be both MT-Safe and Fork-Safe
0N/Aand where possible (almost everywhere), Async-Signal-Safe.
0N/ATo this end, the following rules should be followed:
0N/AAlmost all internal libc locks (mutexes and read-write locks)
0N/Ashould be acquired and released via these interfaces:
0N/A mutex_t some_lock = DEFAULTMUTEX;
0N/A lmutex_lock(&some_lock);
0N/A ... do something critical ...
0N/A lmutex_unlock(&some_lock);
0N/A rwlock_t some_rw_lock = DEFAULTRWLOCK;
0N/A lrw_rdlock(&some_rw_lock);
0N/A ... multiple threads can do something ...
0N/A lrw_unlock(&some_rw_lock);
0N/A lrw_wrlock(&some_rw_lock);
0N/A ... only one thread can do something ...
0N/A lrw_unlock(&some_rw_lock);
0N/AThe above l* versions of the mutex and rwlock interfaces do more
0N/Athan the ordinary interfaces: They define critical regions in
0N/Awhich the calling thread cannot be suspended (making the region
0N/Afork-safe) and in which the calling thread has all signals deferred
0N/A(making the region async-signal-safe).
0N/AHowever, certain rules apply to the code within these critical regions:
0N/A - The code must be of guaranteed short duration; no calls
0N/A to interfaces that might block indefinitely are allowed.
0N/A This means no calls into stdio or syslog() and no calls
0N/A to cond_wait() unless there is a guarantee of an almost-
0N/A immediate call to cond_signal() or cond_broadcast()
0N/A - The code cannot call any non-l* synchronization
0N/A primitives (mutex_lock(), _private_mutex_lock(),
0N/A rw_wrlock(), rw_rdlock(), sema_wait(), etc.)
0N/A - The code cannot call any functions outside of libc,
0N/A including application callbacks and functions from
0N/A dlopen()ed objects, such as those in the I18N code.
0N/A - Because malloc(), calloc(), realloc(), and free()
0N/A are designed to be interposed upon, they fall into
0N/A the previous case of prohibition. None of these can
0N/A be called by a thread while in a critical region.
0N/AThere is a private memory allocator for use internally to libc.
0N/AIt cannot be interposed upon and it is safe to use while in
0N/Aa critical region (or for that matter while not in a critical
0N/Aregion; it is async-signal-safe and fork-safe):
0N/A void *lmalloc(size_t);
0N/A void lfree(void *, size_t);
0N/A void *libc_malloc(size_t);
0N/A void *libc_realloc(void *, size_t);
0N/A char *libc_strdup(const char *);
0N/A void libc_free(void *);
0N/Almalloc() and lfree() are the basic interfaces. The libc_*()
0N/Avariants are built on top of lmalloc()/lfree() but they have
0N/Athe same interface signatures as the corresponding functions
0N/Awithout the 'libc_' prefix. lmalloc() and libc_malloc()
0N/Areturn zeroed memory blocks. Note that lmalloc()/lfree()
0N/Arequire the caller to remember the size parameter passed
0N/Ato lmalloc() and to pass the same value to lfree().
0N/AMemory allocated by lmalloc() can only be freed by lfree().
0N/AMemory allocated by libc_malloc(), libc_realloc(), or libc_strdup()
0N/Acan only be freed by libc_free(). Never pass such allocated
0N/Amemory out of libc if the caller of libc is expected to free it.
0N/Almalloc()/lfree() is a small and simple power of two allocator.
0N/ADo not use it as a general-purpose allocator. Be kind to it.
0N/AThere is a special mutual exclusion interface that exists for
0N/Acases, like code in the I18N interfaces, where mutual exclusion
0N/Ais required but the above rules cannot be followed:
0N/A int fork_lock_enter(const char *);
0N/A void fork_lock_exit(void);
0N/Afork_lock_enter() does triple-duty. Not only does it serialize
0N/Acalls to fork() and forkall(), but it also serializes calls to
0N/Athr_suspend() (fork() and forkall() also suspend other threads),
0N/Aand furthermore it serializes I18N calls to functions in other
0N/Adlopen()ed L10N objects that might be calling malloc()/free().
0N/AUse it in general like this:
0N/A (void) fork_lock_enter(NULL);
0N/A ... serialized; do something that might call malloc ...
0N/AThe 'const char *' argument to fork_lock_enter() should always
0N/Abe NULL except for two special cases:
0N/A - When called from fork() or forkall()
0N/A - When called from pthread_atfork()
0N/AThis enforces the prohibition against calling fork() or pthread_atfork()
0N/Afrom a pthread_atfork()-registered fork handler function while a fork()
0N/Aprologue or epilogue is in progress. If _THREAD_ERROR_DETECTION is set
0N/Ato 1 or 2 in the environment, such cases will draw a nasty message and
0N/Awill dump core if _THREAD_ERROR_DETECTION=2. fork_lock_enter() returns
0N/Anon-zero only if it is called from a fork handler. This is of interest
0N/Aonly to callers that have to do something about this condition; the
0N/Areturn value should be ignored in all other cases (fork_lock_enter()
0N/Anever actually fails).
0N/AIt is an error to call fork_lock_enter() while in a critical region
0N/A(that is, while holding any internal libc lock).
0N/AOn return from fork_lock_enter(), no internal libc locks are held
0N/Abut a flag has been set to cause other callers of fork_lock_enter()
0N/Ato delay (via _cond_wait()) until fork_lock_exit() is called.
0N/AThese are the rules to follow for memory allocation:
0N/A - If a function acquires an internal libc lock or is called while
0N/A an internal libc lock is held:
0N/A * The malloc family cannot be used.
0N/A * lmalloc or libc_malloc should be used. The memory must
0N/A be released by lfree or libc_free, respectively.
0N/A * lfree takes an argument to tell the size of the releasing
0N/A memory. If the function does not know the size at the
0N/A releasing point, libc_malloc and libc_free should be used.
0N/A * As the memory allocated by lmalloc or libc_malloc needs
0N/A to be released by lfree or libc_free and these are internal
0N/A to libc, they cannot be used to allocate memory that might
0N/A be released by application code outside libc.
0N/A * If the memory allocation by malloc() cannot be avoided and
0N/A the scalability of the function does not matter much, the
0N/A function can be serialized with fork_lock_enter() instead
0N/A * If the memory allocation by malloc() cannot be avoided and
0N/A the scalability of the function does matter, another
0N/A implementation of the function will be necessary.
0N/AIn a DEBUG build of libc:
0N/A make THREAD_DEBUG=-DTHREAD_DEBUG install
0N/Amany of these rules are enforced by ASSERT() statements scattered about
0N/Ain the libc sources. This is the default mode for building libc when
0N/Aa DEBUG nightly build is performed.
0N/AThe putback of the project:
0N/A 6416832 libaio and librt can and should be folded into libc
0N/Aintroduced several libc-private locking interfaces:
0N/A void sig_mutex_lock(mutex_t *);
0N/A void sig_mutex_unlock(mutex_t *);
0N/A int sig_mutex_trylock(mutex_t *);
0N/A int sig_cond_wait(cond_t *, mutex_t *);
0N/A int sig_cond_reltimedwait(cond_t *, mutex_t *, const timespec_t *);
0N/AThey are used in specialized code in libc, like the asynchronous i/o code.
0N/AUnlike the lmutex_lock() and lmutex_unlock() interfaces described above,
0N/Athese interfaces do not define critical regions, but signals are
0N/Adeferred while locks acquired by these functions are held, making
0N/Atheir use be async-signal safe. Calls to malloc(), calloc(), realloc(),
0N/Aand free() are permissible while holding such locks.
0N/AThese interfaces were brought over from code in the former libaio
0N/Aand librt and are necessary because, where they are used, the code
0N/Amust execute potentially long-term waits and must be cancelable.
0N/Asig_cond_wait() and sig_cond_reltimedwait() are cancellation points.
0N/AThese interfaces are available for other uses inside libc, as
0N/Athe need arises. (There is no need if the code does not perform
0N/Along-term waits.) Just follow a few rules to be self-consistent:
0N/A - Don't mix calls to mutex_[un]lock(), lmutex_[un]lock() and
0N/A sig_mutex_[un]lock() on the same mutex.
0N/A - Don't call cond_wait() with a mutex acquired by sig_mutex_lock();
0N/A call sig_cond_wait() or sig_cond_reltimedwait().
0N/A - Use pthread_cleanup_push() and pthread_cleanup_pop() to make
0N/A your code cancellation-safe.
0N/A - The sig_*() interfaces are not in themselves fork-safe.
0N/A You have to employ other logic to make your code fork-safe.
0N/A See the tail of postfork1_child() for examples.