summaryrefslogtreecommitdiff
path: root/mozglue/build/BionicGlue.cpp
blob: 208fcce68c82e458af4c202188650463bc273f88 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <android/log.h>
#include <sys/syscall.h>

#include "mozilla/Alignment.h"

#include <vector>

#define NS_EXPORT __attribute__ ((visibility("default")))

#if ANDROID_VERSION < 17 || defined(MOZ_WIDGET_ANDROID)
/* Android doesn't have pthread_atfork(), so we need to use our own. */
struct AtForkFuncs {
  void (*prepare)(void);
  void (*parent)(void);
  void (*child)(void);
};

/* jemalloc's initialization calls pthread_atfork. When pthread_atfork (see
 * further below) stores the corresponding data, it's going to allocate memory,
 * which will loop back to jemalloc's initialization, leading to a dead-lock.
 * So, for that specific vector, we use a special allocator that returns a
 * static buffer for small sizes, and force the initial vector capacity to
 * a size enough to store one atfork function table. */
template <typename T>
struct SpecialAllocator: public std::allocator<T>
{
  SpecialAllocator(): bufUsed(false) {}

  inline typename std::allocator<T>::pointer allocate(typename std::allocator<T>::size_type n, const void * = 0) {
    if (!bufUsed && n == 1) {
      bufUsed = true;
      return buf.addr();
    }
    return reinterpret_cast<T *>(::operator new(sizeof(T) * n));
  }

  inline void deallocate(typename std::allocator<T>::pointer p, typename std::allocator<T>::size_type n) {
    if (p == buf.addr())
      bufUsed = false;
    else
      ::operator delete(p);
  }

  template<typename U>
  struct rebind {
    typedef SpecialAllocator<U> other;
  };

private:
  mozilla::AlignedStorage2<T> buf;
  bool bufUsed;
};

static std::vector<AtForkFuncs, SpecialAllocator<AtForkFuncs> > atfork;
#endif

#ifdef MOZ_WIDGET_GONK
#include "cpuacct.h"

#if ANDROID_VERSION < 17 || defined(MOZ_WIDGET_ANDROID)
extern "C" NS_EXPORT int
timer_create(clockid_t, struct sigevent*, timer_t*)
{
  __android_log_print(ANDROID_LOG_ERROR, "BionicGlue", "timer_create not supported!");
  abort();
  return -1;
}
#endif

#else
#define cpuacct_add(x)
#endif

#if ANDROID_VERSION < 17 || defined(MOZ_WIDGET_ANDROID)
extern "C" NS_EXPORT int
pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
{
  AtForkFuncs funcs;
  funcs.prepare = prepare;
  funcs.parent = parent;
  funcs.child = child;
  if (!atfork.capacity())
    atfork.reserve(1);
  atfork.push_back(funcs);
  return 0;
}

extern "C" NS_EXPORT pid_t __fork(void);

extern "C" NS_EXPORT pid_t
fork(void)
{
  pid_t pid;
  for (auto it = atfork.rbegin();
       it < atfork.rend(); ++it)
    if (it->prepare)
      it->prepare();

  switch ((pid = syscall(__NR_clone, SIGCHLD, NULL, NULL, NULL, NULL))) {
  case 0:
    cpuacct_add(getuid());
    for (auto it = atfork.begin();
         it < atfork.end(); ++it)
      if (it->child)
        it->child();
    break;
  default:
    for (auto it = atfork.begin();
         it < atfork.end(); ++it)
      if (it->parent)
        it->parent();
  }
  return pid;
}
#endif

extern "C" NS_EXPORT int
raise(int sig)
{
  // Bug 741272: Bionic incorrectly uses kill(), which signals the
  // process, and thus could signal another thread (and let this one
  // return "successfully" from raising a fatal signal).
  //
  // Bug 943170: POSIX specifies pthread_kill(pthread_self(), sig) as
  // equivalent to raise(sig), but Bionic also has a bug with these
  // functions, where a forked child will kill its parent instead.

  extern pid_t gettid(void);
  return syscall(__NR_tgkill, getpid(), gettid(), sig);
}

/* Flash plugin uses symbols that are not present in Android >= 4.4 */
#ifndef MOZ_WIDGET_GONK
namespace android {
  namespace VectorImpl {
    NS_EXPORT void reservedVectorImpl1(void) { }
    NS_EXPORT void reservedVectorImpl2(void) { }
    NS_EXPORT void reservedVectorImpl3(void) { }
    NS_EXPORT void reservedVectorImpl4(void) { }
    NS_EXPORT void reservedVectorImpl5(void) { }
    NS_EXPORT void reservedVectorImpl6(void) { }
    NS_EXPORT void reservedVectorImpl7(void) { }
    NS_EXPORT void reservedVectorImpl8(void) { }
  }
}
#endif