继续看一下 glibc 的代码. 继续内存同步这一块. 实际是 pthreads 相关函数.
PS: 好像很多实现都在 hurd 里面.
<!--more -->
先认识一些基础的数据结构.
struct hurd_sigstate
{
spin_lock_t critical_section_lock; /* Held if in critical section. */
spin_lock_t lock; /* Locks most of the rest of the structure. */
thread_t thread; // 线程ID
struct hurd_sigstate *next; /* Linked-list of thread sigstates. */
// sigset_t 是一个由 unsigned long int 组成的数组
// 其最大长度为: 1024 / 8 * sizeof (unsigned long int)
sigset_t blocked; /* What signals are blocked. */
sigset_t pending; /* Pending signals, possibly blocked. */
/* Signal handlers. ACTIONS[0] is used to mark the threads with POSIX
semantics: if sa_handler is SIG_IGN instead of SIG_DFL, this thread
will receive global signals and use the process-wide action vector
instead of this one. */
struct sigaction actions[_NSIG];
stack_t sigaltstack;
/* Chain of thread-local signal preemptors; see <hurd/sigpreempt.h>.
Each element of this chain is in local stack storage, and the chain
parallels the stack: the head of this chain is in the innermost
stack frame, and each next element in an outermore frame. */
struct hurd_signal_preemptor *preemptors;
/* For each signal that may be pending, the details to deliver it with. */
struct hurd_signal_detail pending_data[_NSIG];
/* If `suspended' is set when this thread gets a signal,
the signal thread sends an empty message to it. */
mach_port_t suspended;
/* The following members are not locked. They are used only by this
thread, or by the signal thread with this thread suspended. */
volatile mach_port_t intr_port; /* Port interruptible RPC was sent on. */
/* If this is not null, the thread is in sigreturn awaiting delivery of
pending signals. This context (the machine-dependent portions only)
will be passed to sigreturn after running the handler for a pending
signal, instead of examining the thread state. */
struct sigcontext *context;
/* This is the head of the thread's list of active resources; see
<hurd/userlink.h> for details. This member is only used by the
thread itself, and always inside a critical section. */
struct hurd_userlink *active_resources;
/* These are locked normally. */
int cancel; /* Flag set by hurd_thread_cancel. */
void (*cancel_hook) (void); /* Called on cancellation. */
};
/* Linked list of states of all threads whose state has been asked for. */
emm... 看不懂... Orz
姑且先理解为: 信号相关配置.
这代码量. 不愧是 fork 呢...
我看不懂! 差了太多必要的东西了. 我裂开了... 不! cas 你行的.

cas 你可以的!
那么, 一点一点来分析. (因为神秘缘故上面代码没有语法高亮(已经删除了). 所以这也拆开也比较好!)
/* Clone the calling process, creating an exact copy.
Return -1 for errors, 0 to the new process,
and the process ID of the new process to the old process. */
pid_t
__fork (void)
{
jmp_buf env; // jmp_buf 是个后续会用到的值
pid_t pid; // 很显然就是子进程 ID 了
size_t i;
error_t err;
struct hurd_sigstate *volatile ss;
// 2013-10-04 Samuel Thibault <samuel.thibault@ens-lyon.org>
//
// * sysdeps/mach/hurd/fork.c (_hurd_atfork_prepare_hook)
// (_hurd_atfork_child_hook, _hurd_atfork_parent_hook): New hooks.
// (__fork): Call _hurd_atfork_prepare_hook hooks before all locking, call
// _hurd_atfork_parent_hook or _hurd_atfork_child_hook after all unlocking.
// 关于这个, 我找到了上述日志. (可惜是 13 年的, 不然想去打扰一下作者)
// 看起来是在 fork 时的准备工作.
RUN_HOOK (_hurd_atfork_prepare_hook, ())
ss = _hurd_self_sigstate ();
__spin_lock (&ss->critical_section_lock);
#undef LOSE
#define LOSE do { assert_perror (err); goto lose; } while (0) /* XXX */
// 关于 _hurd_atfork_prepare_hook :
struct atfork
{
void (*prepare) (void);
void (*parent) (void);
void (*child) (void);
void *dso_handle;
struct atfork *prev;
struct atfork *next;
};
/* TODO: better locking */
__libc_lock_define_initialized (static, atfork_lock);
static struct atfork *fork_handlers, *fork_last_handler;
// 这个函数的意图挺好理解的, 循环遍历. 执行准备工作.
// 不过问题是, 这些工作是从哪里设置的 = =
// fork_handles 和 fork_last_handler 看起来应该是有一段'距离'的, 这又是哪里设置的呢 = =
static void
atfork_pthread_prepare (void)
{
struct atfork *handlers, *last_handler;
__libc_lock_lock (atfork_lock);
handlers = fork_handlers;
last_handler = fork_last_handler;
__libc_lock_unlock (atfork_lock);
if (last_handler == NULL)
return;
while (1)
{
if (last_handler->prepare != NULL)
last_handler->prepare ();
if (last_handler == handlers)
break;
last_handler = last_handler->prev;
}
}
text_set_element (_hurd_atfork_prepare_hook, atfork_pthread_prepare);
// 关于setjmp: [link](<https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.1.0/com.ibm.zos.v2r1.bpxbd00/setjmp.htm>)
// 简而言之, 它会保存当前环境, 而之后在 longjmp 则会返回到当前环境.
// 而此时, setjmp 返回非 0. 类似于一个开关.
if (! setjmp (env))
{
// 这部分看起来是在准备变量
process_t newproc;
task_t newtask;
thread_t thread, sigthread;
mach_port_urefs_t thread_refs, sigthread_refs;
struct machine_thread_state state;
mach_msg_type_number_t statecount;
mach_port_t *portnames = NULL;
mach_msg_type_number_t nportnames = 0;
mach_port_type_t *porttypes = NULL;
mach_msg_type_number_t nporttypes = 0;
thread_t *threads = NULL;
mach_msg_type_number_t nthreads = 0;
int ports_locked = 0, stopped = 0;
// 这里是我极其疑惑的一点. 这不是函数定义么?
// 函数中函数定义? 不可以这么做啊... Orz
void resume_threads (void)
{
if (! stopped)
return;
assert (threads);
for (i = 0; i < nthreads; ++i)
if (threads[i] != ss->thread)
__thread_resume (threads[i]);
stopped = 0;
}
/* Run things that prepare for forking before we create the task. */
RUN_HOOK (_hurd_fork_prepare_hook, ());
/* Lock things that want to be locked before we fork. */
{
void *const *p;
for (p = symbol_set_first_element (_hurd_fork_locks);
! symbol_set_end_p (_hurd_fork_locks, p);
++p)
__mutex_lock (*p);
}
__mutex_lock (&_hurd_siglock);