1c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes/*
2c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes * Copyright (C) 2008 The Android Open Source Project
3c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes * All rights reserved.
4c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes *
5c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes * Redistribution and use in source and binary forms, with or without
6c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes * modification, are permitted provided that the following conditions
7c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes * are met:
8c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes *  * Redistributions of source code must retain the above copyright
9c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes *    notice, this list of conditions and the following disclaimer.
10c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes *  * Redistributions in binary form must reproduce the above copyright
11c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes *    notice, this list of conditions and the following disclaimer in
12c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes *    the documentation and/or other materials provided with the
13c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes *    distribution.
14c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes *
15c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes * SUCH DAMAGE.
27c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes */
28c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes
29c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes#include <errno.h>
30c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes#include <pthread.h>
31c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes
32c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughesstruct atfork_t {
33c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  atfork_t* next;
34c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  atfork_t* prev;
35c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes
36c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  void (*prepare)(void);
37c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  void (*child)(void);
38c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  void (*parent)(void);
39c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes};
40c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes
41c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughesstruct atfork_list_t {
42c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  atfork_t* first;
43c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  atfork_t* last;
44c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes};
45c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes
461728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic pthread_mutex_t g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
471728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic atfork_list_t g_atfork_list = { NULL, NULL };
48c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes
49c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughesvoid __bionic_atfork_run_prepare() {
504b558f50a42c97d461f1dede5aaaae490ea99e2eElliott Hughes  // We lock the atfork list here, unlock it in the parent, and reset it in the child.
51c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  // This ensures that nobody can modify the handler array between the calls
52c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  // to the prepare and parent/child handlers.
53c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  //
544b558f50a42c97d461f1dede5aaaae490ea99e2eElliott Hughes  // TODO: If a handler tries to mutate the list, they'll block. We should probably copy
554b558f50a42c97d461f1dede5aaaae490ea99e2eElliott Hughes  // the list before forking, and have prepare, parent, and child all work on the consistent copy.
561728b2396591853345507a063ed6075dfd251706Elliott Hughes  pthread_mutex_lock(&g_atfork_list_mutex);
57c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes
58c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  // Call pthread_atfork() prepare handlers. POSIX states that the prepare
59c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  // handlers should be called in the reverse order of the parent/child
60c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  // handlers, so we iterate backwards.
611728b2396591853345507a063ed6075dfd251706Elliott Hughes  for (atfork_t* it = g_atfork_list.last; it != NULL; it = it->prev) {
62c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes    if (it->prepare != NULL) {
63c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes      it->prepare();
64c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes    }
65c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  }
66c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes}
67c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes
68c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughesvoid __bionic_atfork_run_child() {
691728b2396591853345507a063ed6075dfd251706Elliott Hughes  for (atfork_t* it = g_atfork_list.first; it != NULL; it = it->next) {
70c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes    if (it->child != NULL) {
71c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes      it->child();
72c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes    }
73c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  }
74c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes
751728b2396591853345507a063ed6075dfd251706Elliott Hughes  g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
76c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes}
77c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes
78c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughesvoid __bionic_atfork_run_parent() {
791728b2396591853345507a063ed6075dfd251706Elliott Hughes  for (atfork_t* it = g_atfork_list.first; it != NULL; it = it->next) {
80c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes    if (it->parent != NULL) {
81c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes      it->parent();
82c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes    }
83c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  }
84c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes
851728b2396591853345507a063ed6075dfd251706Elliott Hughes  pthread_mutex_unlock(&g_atfork_list_mutex);
86c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes}
87c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes
88c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughesint pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void)) {
89c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  atfork_t* entry = reinterpret_cast<atfork_t*>(malloc(sizeof(atfork_t)));
90c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  if (entry == NULL) {
91c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes    return ENOMEM;
92c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  }
93c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes
94c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  entry->prepare = prepare;
95c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  entry->parent = parent;
96c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  entry->child = child;
97c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes
981728b2396591853345507a063ed6075dfd251706Elliott Hughes  pthread_mutex_lock(&g_atfork_list_mutex);
99c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes
100c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  // Append 'entry' to the list.
101c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  entry->next = NULL;
1021728b2396591853345507a063ed6075dfd251706Elliott Hughes  entry->prev = g_atfork_list.last;
103c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  if (entry->prev != NULL) {
104c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes    entry->prev->next = entry;
105c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  }
1061728b2396591853345507a063ed6075dfd251706Elliott Hughes  if (g_atfork_list.first == NULL) {
1071728b2396591853345507a063ed6075dfd251706Elliott Hughes    g_atfork_list.first = entry;
108c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  }
1091728b2396591853345507a063ed6075dfd251706Elliott Hughes  g_atfork_list.last = entry;
110c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes
1111728b2396591853345507a063ed6075dfd251706Elliott Hughes  pthread_mutex_unlock(&g_atfork_list_mutex);
112c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes
113c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes  return 0;
114c3f114037dbf028896310609fd28cf2b3da99c4dElliott Hughes}
115