Home | History | Annotate | Download | only in bionic
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in
     12  *    the documentation and/or other materials provided with the
     13  *    distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
     22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <errno.h>
     30 #include <pthread.h>
     31 #include <stdlib.h>
     32 
     33 #include "private/bionic_macros.h"
     34 
     35 struct atfork_t {
     36   atfork_t* next;
     37   atfork_t* prev;
     38 
     39   void (*prepare)(void);
     40   void (*child)(void);
     41   void (*parent)(void);
     42 
     43   void* dso_handle;
     44 };
     45 
     46 class atfork_list_t {
     47  public:
     48   constexpr atfork_list_t() : first_(nullptr), last_(nullptr) {}
     49 
     50   template<typename F>
     51   void walk_forward(F f) {
     52     for (atfork_t* it = first_; it != nullptr; it = it->next) {
     53       f(it);
     54     }
     55   }
     56 
     57   template<typename F>
     58   void walk_backwards(F f) {
     59     for (atfork_t* it = last_; it != nullptr; it = it->prev) {
     60       f(it);
     61     }
     62   }
     63 
     64   void push_back(atfork_t* entry) {
     65     entry->next = nullptr;
     66     entry->prev = last_;
     67     if (entry->prev != nullptr) {
     68       entry->prev->next = entry;
     69     }
     70     if (first_ == nullptr) {
     71       first_ = entry;
     72     }
     73     last_ = entry;
     74   }
     75 
     76   template<typename F>
     77   void remove_if(F predicate) {
     78     atfork_t* it = first_;
     79     while (it != nullptr) {
     80       if (predicate(it)) {
     81         atfork_t* entry = it;
     82         it = it->next;
     83         remove(entry);
     84       } else {
     85         it = it->next;
     86       }
     87     }
     88   }
     89 
     90  private:
     91   void remove(atfork_t* entry) {
     92     if (entry->prev != nullptr) {
     93       entry->prev->next = entry->next;
     94     } else {
     95       first_ = entry->next;
     96     }
     97 
     98     if (entry->next != nullptr) {
     99       entry->next->prev = entry->prev;
    100     } else {
    101       last_ = entry->prev;
    102     }
    103 
    104     free(entry);
    105   }
    106 
    107   atfork_t* first_;
    108   atfork_t* last_;
    109 
    110   DISALLOW_COPY_AND_ASSIGN(atfork_list_t);
    111 };
    112 
    113 static pthread_mutex_t g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
    114 static atfork_list_t g_atfork_list;
    115 
    116 void __bionic_atfork_run_prepare() {
    117   // We lock the atfork list here, unlock it in the parent, and reset it in the child.
    118   // This ensures that nobody can modify the handler array between the calls
    119   // to the prepare and parent/child handlers.
    120   pthread_mutex_lock(&g_atfork_list_mutex);
    121 
    122   // Call pthread_atfork() prepare handlers. POSIX states that the prepare
    123   // handlers should be called in the reverse order of the parent/child
    124   // handlers, so we iterate backwards.
    125   g_atfork_list.walk_backwards([](atfork_t* it) {
    126     if (it->prepare != nullptr) {
    127       it->prepare();
    128     }
    129   });
    130 }
    131 
    132 void __bionic_atfork_run_child() {
    133   g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
    134 
    135   pthread_mutex_lock(&g_atfork_list_mutex);
    136   g_atfork_list.walk_forward([](atfork_t* it) {
    137     if (it->child != nullptr) {
    138       it->child();
    139     }
    140   });
    141   pthread_mutex_unlock(&g_atfork_list_mutex);
    142 }
    143 
    144 void __bionic_atfork_run_parent() {
    145   g_atfork_list.walk_forward([](atfork_t* it) {
    146     if (it->parent != nullptr) {
    147       it->parent();
    148     }
    149   });
    150 
    151   pthread_mutex_unlock(&g_atfork_list_mutex);
    152 }
    153 
    154 // __register_atfork is the name used by glibc
    155 extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void),
    156                                  void(*child)(void), void* dso) {
    157   atfork_t* entry = reinterpret_cast<atfork_t*>(malloc(sizeof(atfork_t)));
    158   if (entry == nullptr) {
    159     return ENOMEM;
    160   }
    161 
    162   entry->prepare = prepare;
    163   entry->parent = parent;
    164   entry->child = child;
    165   entry->dso_handle = dso;
    166 
    167   pthread_mutex_lock(&g_atfork_list_mutex);
    168 
    169   g_atfork_list.push_back(entry);
    170 
    171   pthread_mutex_unlock(&g_atfork_list_mutex);
    172 
    173   return 0;
    174 }
    175 
    176 extern "C" __LIBC_HIDDEN__ void __unregister_atfork(void* dso) {
    177   pthread_mutex_lock(&g_atfork_list_mutex);
    178   g_atfork_list.remove_if([&](const atfork_t* entry) {
    179     return entry->dso_handle == dso;
    180   });
    181   pthread_mutex_unlock(&g_atfork_list_mutex);
    182 }
    183 
    184