linux/bootstrap: documented the reasoning for locking memory calls
[AROS.git] / arch / all-linux / bootstrap / malloc.c
blob2f858228d0fd873fca3939ab6b8a30708253bed2
1 /*
2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 /*
7 * AROS-thread-safe versions of libc memory allocation routines
8 * This does not work with Android's bionic.
9 */
12 Explanation:
14 Forbid-locking is needed because AROS must protect calls to Linux memory
15 allocation functions against reentrancy. Linux malloc's pthread mutex
16 protection (or whatever it uses) will not work, because that one protects
17 Linux thread #1 against other Linux threads. However AROS tasks are all
18 inside the same Linux thread.
20 So if AROS task #1 is in the middle of Linux malloc, AROS task #2 may end
21 up doing Linux malloc call as well and when it hits Linux malloc's
22 pthread mutex (or whatever protection), that one will see that lock is being
23 held, but by same thread. If the used Linux locking allows nesting it causes
24 havoc (2 malloc's running at the same time). If it doesn't allow nesting,
25 it will hang.
27 The locking is only valid inside the AROS Linux thread. Other threads within
28 AROS process do not need it, because it will be handled by Linux malloc's
29 pthread mutex. Moreover, calling Forbid() from multiple Linux threads will
30 cause the TDNestCnt to become damaged.
32 TDNestCnt is "per task" and while other Linux thread calls Forbid() the AROS
33 Linux thread may be running AROS task #1. Then when that other Linux thread
34 does matching Permit(), AROS Linux thread may have already switched to
35 another AROS task. So the effect is like AROS task #1 calling Forbid() and
36 AROS task #2 calling Permit().
39 /* TODO:
40 This code is compiled with the kernel compiler but calls code
41 from exec.library. This can only work if function calling
42 convention for kernel and target compiler are the same.
43 Up to now this seems to be the case for all linux hosted ports
44 as UNIX calling is often taken as reference for the AROS
45 implementation.
48 #ifndef __ANDROID__
50 #include <proto/exec.h>
51 #include <sys/types.h>
53 #include <unistd.h>
54 #include <syscall.h>
56 static int memnest;
57 extern pid_t arostid;
59 #define THREADID pid_t thistid = syscall(SYS_gettid);
60 #define MEMLOCK if (SysBase != NULL && thistid == arostid) Forbid();
61 #define MEMUNLOCK if (SysBase != NULL && thistid == arostid) Permit();
63 extern struct ExecBase *SysBase;
64 extern void * __libc_malloc(size_t);
65 extern void __libc_free(void *);
66 extern void * __libc_calloc(size_t, size_t);
67 extern void * __libc_realloc(void * mem, size_t newsize);
69 void * malloc(size_t size)
71 void *res;
72 THREADID
74 MEMLOCK
75 memnest++;
76 res = __libc_malloc(size);
77 memnest--;
78 MEMUNLOCK
80 return res;
83 void free(void * addr)
85 THREADID
87 MEMLOCK
88 memnest++;
89 __libc_free(addr);
90 memnest--;
91 MEMUNLOCK
94 void * calloc(size_t n, size_t size)
96 void *res;
97 THREADID
99 MEMLOCK
100 memnest++;
101 res = __libc_calloc(n, size);
102 memnest--;
103 MEMUNLOCK
105 return res;
108 void *realloc(void *ptr, size_t size)
110 void *res;
111 THREADID
113 MEMLOCK
114 memnest++;
115 res = __libc_realloc(ptr, size);
116 memnest--;
117 MEMUNLOCK;
119 return res;
122 #endif