summaryrefslogtreecommitdiffstats
path: root/libc/docs/OVERVIEW.TXT
blob: 4d40df6fb1d12cc1391e47d0c608e24902e8ade1 (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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
Bionic C Library Overview:
==========================

Introduction:

Core Philosophy:

  The core idea behind Bionic's design is: KEEP IT REALLY SIMPLE.

  This implies that the C library should only provide lightweight wrappers around kernel
  facilities and not try to be too smart to deal with edge cases.

  The name "Bionic" comes from the fact that it is part-BSD and part-Linux: its source
  code consists in a mix of BSD C library pieces with custom Linux-specific bits used
  to deal with threads, processes, signals and a few others things.

  All original BSD pieces carry the BSD copyright disclaimer. Bionic-specific bits
  carry the Android Open Source Project copyright disclaimer. And everything is released
  under the BSD license.

Architectures:

  Bionic currently supports the ARM and x86 instruction sets. In theory, it should be
  possible to support more, but this may require a little work (e.g. adding system
  call IDs to SYSCALLS.TXT, described below, or modifying the dynamic linker).

  The ARM-specific code is under arch-arm/ and the x86-specific one is under arch-x86/

  Note that the x86 version is only meant to run on an x86 Android device. We make
  absolutely no claim that you could build and use Bionic on a stock x86 Linux
  distribution (though that would be cool, so patches are welcomed :-))

Syscall stubs:

  Each system call function is implemented by a tiny assembler source fragment
  (called a "syscall stub"), which is generated automatically by tools/gensyscalls.py
  which reads the SYSCALLS.TXT file for input.

  SYSCALLS.TXT contains the list of all syscall stubs to generate, along with
  the corresponding syscall numeric identifier (which may differ between ARM and x86),
  and its signature

  If you modify this file, you may want to use tools/checksyscalls.py which checks
  its content against official Linux kernel header files, and will report errors when
  invalid syscall ids are used.

  Sometimes, the C library function is really a wrapper that calls the corresponding
  syscall with another name. For example, the exit() function is provided by the C
  library and calls the _exit() syscall stub.

  See SYSCALLS.TXT for documentation and details.


time_t:

  time_t is 32-bit as defined by the kernel on 32-bit CPUs. A 64-bit version would
  be preferrable to avoid the Y2038 bug, but the kernel maintainers consider that
  this is not needed at the moment.

  Instead, Bionic provides a <time64.h> header that defines a time64_t type, and
  related functions like mktime64(), localtime64(), etc...


Timezone management:

  The name of the current timezone is taken from the TZ environment variable, if defined.
  Otherwise, the system property named 'persist.sys.timezone' is checked instead.

  The zoneinfo timezone database and index files are located under directory
  /system/usr/share/zoneinfo, instead of the more Posix path of /usr/share/zoneinfo


off_t:

  For similar reasons, off_t is 32-bit. We define loff_t as the 64-bit variant due
  to BSD inheritance, but off64_t should be available as a typedef to ease porting of
  current Linux-specific code.



Linux kernel headers:

  Bionic comes with its own set of "clean" Linux kernel headers to allow user-space
  code to use kernel-specific declarations (e.g. IOCTLs, structure declarations,
  constants, etc...). They are located in:

     ./kernel/common,
     ./kernel/arch-arm
     ./kernel/arch-x86

  These headers have been generated by a tool (kernel/tools/update-all.py) to only
  include the public definitions from the original Linux kernel headers.

  If you want to know why and how this is done, read kernel/README.TXT to get
  all the (gory) details.


PThread implementation:

   Bionic's C library comes with its own pthread implementation bundled in. This is
   different from other historical C libraries which:

    - place it in an external library (-lpthread)
    - play linker tricks with weak symbols at dynamic link time

   The support for real-time features (a.k.a. -lrt) is also bundled in the C library.

   The implementation is based on futexes and strives to provide *very* short code paths
   for common operations. Notable features are the following:

      - pthread_mutex_t, pthread_cond_t are only 4 bytes each.

      - Normal, recursive and error-check mutexes are supported, and the code path
        is heavily optimized for the normal case, which is used most of the time.

      - Process-shared mutexes and condition variables are not supported.
        Their implementation requires far more complexity and was absolutely
        not needed for Android (which uses other inter-process synchronization
        capabilities).

        Note that they could be added in the future without breaking the ABI
        by specifying more sophisticated code paths (which may make the common
        paths slightly slower though).

      - There is currently no support for read/write locks, priority-ceiling in
        mutexes and other more advanced features. Again, the main idea being that
        this was not needed for Android at all but could be added in the future.

pthread_cancel():

   pthread_cancel() will *not* be supported in Bionic, because doing this would
   involve making the C library significantly bigger for very little benefit.

   Consider that:

     - A proper implementation must insert pthread cancellation checks in a lot
       of different places of the C library. And conformance is very difficult to
       test properly.

     - A proper implementation must also clean up resources, like releasing memory,
       or unlocking mutexes, properly if the cancellation happens in a complex
       function (e.g. inside gethostbyname() or fprintf() + complex formatting
       rules). This tends to slow down the path of many functions.

     - pthread cancellation cannot stop all threads: e.g. it can't do anything
       against an infinite loop

     - pthread cancellation itself has short-comings and isn't very portable
       (see http://advogato.org/person/slamb/diary.html?start=49 for example).

   All of this is contrary to the Bionic design goals. If your code depends on
   thread cancellation, please consider alternatives.

   Note however that Bionic does implement pthread_cleanup_push() and pthread_cleanup_pop(),
   which can be used to handle cleanups that happen when a thread voluntarily exits
   through pthread_exit() or returning from its main function.


pthread_once():

  Do not call fork() within a callback provided to pthread_once(). Doing this
  may result in a deadlock in the child process the next time it calls pthread_once().

  Also, you can't throw a C++ Exception from the callback (see C++ Exception Support
  below).

  The current implementation of pthread_once() lacks the necessary support of
  multi-core-safe double-checked-locking (read and write barriers).


Thread-specific data

  The thread-specific storage only provides for a bit less than 64 pthread_key_t
  objects to each process. The implementation provides 64 real slots but also
  uses about 5 of them (exact number may depend on implementation) for its
  own use (e.g. two slots are pre-allocated by the C library to speed-up the
  Android OpenGL sub-system).

  Note that Posix mandates a minimum of 128 slots, but we do not claim to be
  Posix-compliant.

  Except for the main thread, the TLS area is stored at the top of the stack. See
  comments in bionic/libc/bionic/pthread.c for details.

  At the moment, thread-local storage defined through the __thread compiler keyword
  is not supported by the Bionic C library and dynamic linker.


Multi-core support

  At the moment, Bionic does not provide or use read/write memory barriers.
  This means that using it on certain multi-core systems might not be supported,
  depending on its exact CPU architecture.


Android-specific features:

  Bionic provides a small number of Android-specific features to its clients:

  - access to system properties:

       Android provides a simple shared value/key space to all processes on the
       system. It stores a liberal number of 'properties', each of them being a
       simple size-limited string that can be associated to a size-limited string
       value.

       The header <sys/system_properties.h> can be used to read system properties
       and also defines the maximum size of keys and values.

   - Android-specific user/group management:

       There is no /etc/passwd or /etc/groups in Android. By design, it is meant to
       be used by a single handset user. On the other hand, Android uses the Linux
       user/group management features extensively to secure process permissions,
       like access to various filesystem directories.

       In the Android scheme, each installed application gets its own uid_t/gid_t
       starting from 10000; lower numerical ids are reserved for system daemons.

       getpwnam() recognizes some hard-coded subsystems names (e.g. "radio") and
       will translate them to their low-user-id values. It also recognizes "app_1234"
       as the synthetic name of the application that was installed with uid 10000 + 1234,
       which is 11234. getgrnam() works similarly

       getgrouplist() will always return a single group for any user name, which is
       the one passed as an input parameter.

       getgrgid() will similarly only return a structure that contains a single-element
       members list, corresponding to the user with the same numerical value than the
       group.

       See bionic/libc/bionic/stubs.c for more details.

    - getservent()

       There is no /etc/services on Android. Instead the C library embeds a constant
       list of services in its executable, which is parsed on demand by the various
       functions that depend on it. See bionic/libc/netbsd/net/getservent.c and
       bionic/libc/netbsd/net/services.h

       The list of services defined internally might change liberally in the future.
       This feature is mostly historically and is very rarely used.

       The getservent() returns thread-local data. getservbyport() and getservbyname()
       are also implemented in a similar fashion.

     - getprotoent()

       There is no /etc/protocol on Android. Bionic does not currently implement
       getprotoent() and related functions. If we add it, it will likely be done
       in a way similar to getservent()

DNS resolver:

  Bionic uses a NetBSD-derived resolver library which has been modified in the following
  ways:

     - don't implement the name-server-switch feature (a.k.a. <nsswitch.h>)

     - read /system/etc/resolv.conf instead of /etc/resolv.conf

     - read the list of servers from system properties. the code looks for
       'net.dns1', 'net.dns2', etc.. Each property should contain the IP address
       of a DNS server.

       these properties are set/modified by other parts of the Android system
       (e.g. the dhcpd daemon).

       the implementation also supports per-process DNS server list, using the
       properties 'net.dns1.<pid>', 'net.dns2.<pid>', etc... Where <pid> stands
       for the numerical ID of the current process.

     - when performing a query, use a properly randomized Query ID (instead of
       a incremented one), for increased security.

     - when performing a query, bind the local client socket to a random port
       for increased security.

     - get rid of *many* unfortunate thread-safety issues in the original code

  Bionic does *not* expose implementation details of its DNS resolver; the content
  of <arpa/nameser.h> is intentionally blank. The resolver implementation might
  change completely in the future.


PThread Real-Time Timers:

  timer_create(), timer_gettime(), timer_settime() and timer_getoverrun() are
  supported.

  Bionic also now supports SIGEV_THREAD real-time timers (see timer_create()).
  The implementation simply uses a single thread per timer, unlike GLibc which
  uses complex heuristics to try to use the less threads possible when several
  timers with compatible properties are used.

  This means that if your code uses a lot of SIGEV_THREAD timers, your program
  may consume a lot of memory. However, if your program needs many of these timers,
  it'd better handle timeout events directly instead.

  Other timers (e.g. SIGEV_SIGNAL) are handled by the kernel and use much less
  system resources.


Binary Compatibility:

  Bionic is *not* in any way binary-compatible with the GNU C Library, ucLibc or any
  known Linux C library. This means several things:

  - You cannot expect to build something against the GNU C Library headers and have
    it dynamically link properly to Bionic later.

  - You should *really* use the Android toolchain to build your program against Bionic.
    The toolchain deals with many important details that are crucial to get something
    working properly.

  Failure to do so will usually result in the inability to run or link your program,
  or even runtime crashes. Several random web pages on the Internet describe how you
  can succesfully write a "hello-world" program with the ARM GNU toolchain. These
  examples usually work by chance, if anything else, and you should not follow these
  instructions unless you want to waste a lot of your time in the process.

  Note however that you *can* generate a binary that is built against the GNU C Library
  headers and then statically linked to it. The corresponding executable should be able
  to run (if it doesn't use dlopen()/dlsym())

Dynamic Linker:

  Bionic comes with its own dynamic linker (just like ld.so on Linux really comes from
  GLibc). This linker does not support all the relocations generated by other GCC ARM
  toolchains.

C++ Exceptions Support:

  At the moment, Bionic doesn't support C++ exceptions, what this really means is the
  following:

    - If pthread_once() is called with a C++ callback that throws an exception,
      then the C library will keep the corresponding pthread_once_t mutex locked.
      Any further call to pthread_once() will result in a deadlock.

      A proper implementation should be able to register a C++ exception cleanup
      handler before the callback to properly unlock the pthread_once_t. Unfortunately
      this requires tricky assembly code that is highly dependent on the compiler.

      This feature is not planned to be supported anytime soon.

    - The same problem may arise if you throw an exception within a callback called
      from the C library. Fortunately, these cases are very rare in the real-world,
      but any callback you provide to the C library should *not* throw an exception.

    - Bionic lacks a few support functions to have exception support work properly.

Include Paths:

  The Android build system should automatically provide the necessary include paths
  required to build against the C library headers. However, if you want to do that
  yourself, you will need to add:

      libc/arch-$ARCH/include
      libc/include
      libc/kernel/common
      libc/kernel/arch-$ARCH

  to your C include path.