Lines 77-82
static mutex_t free_list_lock = _LIBC_LOCK_INITIALIZER;
Link Here
|
77 |
static size_t narenas = 1; |
77 |
static size_t narenas = 1; |
78 |
static mstate free_list; |
78 |
static mstate free_list; |
79 |
|
79 |
|
|
|
80 |
static void |
81 |
write_message (const char *string) |
82 |
{ |
83 |
write (STDERR_FILENO, string, strlen (string)); |
84 |
} |
85 |
|
86 |
static void |
87 |
check_attachment (void) |
88 |
{ |
89 |
if (thread_arena != NULL) |
90 |
{ |
91 |
mutex_lock (&free_list_lock); |
92 |
if (thread_arena->attached_threads == 0) |
93 |
{ |
94 |
char buf[256]; |
95 |
__snprintf (buf, sizeof (buf), |
96 |
"Current arena %p has zero attached threads.", |
97 |
thread_arena); |
98 |
write_message (buf); |
99 |
for (mstate p = &main_arena; ; ) |
100 |
{ |
101 |
__snprintf (buf, sizeof (buf), " %p (next_free: %p) %zu%s\n", |
102 |
p, p->next_free, p->attached_threads, |
103 |
p == thread_arena ? " *" : ""); |
104 |
write_message (buf); |
105 |
p = p->next; |
106 |
if (p == &main_arena) |
107 |
break; |
108 |
} |
109 |
abort (); |
110 |
} |
111 |
mutex_unlock (&free_list_lock); |
112 |
} |
113 |
} |
114 |
|
115 |
static void |
116 |
check_free_list_nolock (const char *func, const char *place) |
117 |
{ |
118 |
size_t list_length = 0; |
119 |
for (mstate current = free_list; current != NULL; |
120 |
current = current->next_free) |
121 |
{ |
122 |
++list_length; |
123 |
|
124 |
/* See if the arena appears in the first list_length - 1 |
125 |
arenas as well. */ |
126 |
mstate p = free_list; |
127 |
for (int j = 1; j < list_length; ++j) |
128 |
{ |
129 |
if (p == current) |
130 |
{ |
131 |
char buf[256]; |
132 |
__snprintf (buf, sizeof (buf), |
133 |
"Arena free list cycle detected (%s, %s):\n", |
134 |
func, place); |
135 |
write_message (buf); |
136 |
/* Start from the beginning and print the first |
137 |
list_length items. */ |
138 |
p = free_list; |
139 |
for (int j = 0; j < list_length; ++j) |
140 |
{ |
141 |
__snprintf (buf, sizeof (buf), " %p %zu%s\n", |
142 |
p, p->attached_threads, |
143 |
p == current ? " *" : ""); |
144 |
write_message (buf); |
145 |
p = p->next_free; |
146 |
} |
147 |
__snprintf (buf, sizeof (buf), "Total arena count: %zu\n", |
148 |
atomic_load_relaxed (&narenas)); |
149 |
write_message (buf); |
150 |
|
151 |
for (p = &main_arena; ; ) |
152 |
{ |
153 |
__snprintf (buf, sizeof (buf), " %p (next_free: %p) %zu%s\n", |
154 |
p, p->next_free, p->attached_threads, |
155 |
p == current ? " *" : ""); |
156 |
write_message (buf); |
157 |
p = p->next; |
158 |
if (p == &main_arena) |
159 |
break; |
160 |
} |
161 |
abort (); |
162 |
} |
163 |
p = p->next_free; |
164 |
} |
165 |
} |
166 |
} |
167 |
|
168 |
static void |
169 |
check_free_list (const char *func, const char *place) |
170 |
{ |
171 |
mutex_lock (&free_list_lock); |
172 |
check_free_list_nolock (func, place); |
173 |
mutex_unlock (&free_list_lock); |
174 |
} |
175 |
|
80 |
/* list_lock prevents concurrent writes to the next member of struct |
176 |
/* list_lock prevents concurrent writes to the next member of struct |
81 |
malloc_state objects. |
177 |
malloc_state objects. |
82 |
|
178 |
|
Lines 106-111
int __malloc_initialized = -1;
Link Here
|
106 |
in the new arena. */ |
202 |
in the new arena. */ |
107 |
|
203 |
|
108 |
#define arena_get(ptr, size) do { \ |
204 |
#define arena_get(ptr, size) do { \ |
|
|
205 |
check_attachment (); \ |
109 |
ptr = thread_arena; \ |
206 |
ptr = thread_arena; \ |
110 |
arena_lock (ptr, size); \ |
207 |
arena_lock (ptr, size); \ |
111 |
} while (0) |
208 |
} while (0) |
Lines 670-675
_int_new_arena (size_t size)
Link Here
|
670 |
thread_arena = a; |
767 |
thread_arena = a; |
671 |
mutex_init (&a->mutex); |
768 |
mutex_init (&a->mutex); |
672 |
|
769 |
|
|
|
770 |
check_free_list (__func__, "before link-in"); |
771 |
|
673 |
(void) mutex_lock (&list_lock); |
772 |
(void) mutex_lock (&list_lock); |
674 |
|
773 |
|
675 |
/* Add the new arena to the global list. */ |
774 |
/* Add the new arena to the global list. */ |
Lines 682-690
_int_new_arena (size_t size)
Link Here
|
682 |
|
781 |
|
683 |
(void) mutex_unlock (&list_lock); |
782 |
(void) mutex_unlock (&list_lock); |
684 |
|
783 |
|
|
|
784 |
check_free_list (__func__, "before detach"); |
685 |
(void) mutex_lock (&free_list_lock); |
785 |
(void) mutex_lock (&free_list_lock); |
686 |
detach_arena (replaced_arena); |
786 |
detach_arena (replaced_arena); |
687 |
(void) mutex_unlock (&free_list_lock); |
787 |
(void) mutex_unlock (&free_list_lock); |
|
|
788 |
check_free_list (__func__, "after detach"); |
688 |
|
789 |
|
689 |
/* Lock this arena. NB: Another thread may have been attached to |
790 |
/* Lock this arena. NB: Another thread may have been attached to |
690 |
this arena because the arena is now accessible from the |
791 |
this arena because the arena is now accessible from the |
Lines 702-712
_int_new_arena (size_t size)
Link Here
|
702 |
} |
803 |
} |
703 |
|
804 |
|
704 |
|
805 |
|
705 |
/* Remove an arena from free_list. The arena may be in use because it |
806 |
/* Remove an arena from free_list. */ |
706 |
was attached concurrently to a thread by reused_arena below. */ |
|
|
707 |
static mstate |
807 |
static mstate |
708 |
get_free_list (void) |
808 |
get_free_list (void) |
709 |
{ |
809 |
{ |
|
|
810 |
check_free_list (__func__, "start"); |
710 |
mstate replaced_arena = thread_arena; |
811 |
mstate replaced_arena = thread_arena; |
711 |
mstate result = free_list; |
812 |
mstate result = free_list; |
712 |
if (result != NULL) |
813 |
if (result != NULL) |
Lines 718-724
get_free_list (void)
Link Here
|
718 |
free_list = result->next_free; |
819 |
free_list = result->next_free; |
719 |
|
820 |
|
720 |
/* The arena will be attached to this thread. */ |
821 |
/* The arena will be attached to this thread. */ |
721 |
++result->attached_threads; |
822 |
assert (result->attached_threads == 0); |
|
|
823 |
result->attached_threads = 1; |
722 |
|
824 |
|
723 |
detach_arena (replaced_arena); |
825 |
detach_arena (replaced_arena); |
724 |
} |
826 |
} |
Lines 732-740
get_free_list (void)
Link Here
|
732 |
} |
834 |
} |
733 |
} |
835 |
} |
734 |
|
836 |
|
|
|
837 |
check_attachment (); |
838 |
if (result != NULL) |
839 |
{ |
840 |
(void) mutex_lock (&free_list_lock); |
841 |
check_free_list_nolock (__func__, "after detach/attach"); |
842 |
/* We know that the free list does not contain a loop. */ |
843 |
for (mstate p = free_list; p != NULL; p = p->next_free) |
844 |
if (p == result) |
845 |
{ |
846 |
char buf[256]; |
847 |
__snprintf (buf, sizeof (buf), |
848 |
"get_free_list returns arena %p still on free list:", |
849 |
thread_arena); |
850 |
write_message (buf); |
851 |
|
852 |
for (p = free_list; p != NULL; p = p->next_free) |
853 |
{ |
854 |
__snprintf (buf, sizeof (buf), " %p %zu%s\n", |
855 |
p, p->attached_threads, |
856 |
p == result ? " *" : ""); |
857 |
write_message (buf); |
858 |
} |
859 |
|
860 |
for (p = &main_arena; ; ) |
861 |
{ |
862 |
__snprintf (buf, sizeof (buf), " %p (next_free: %p) %zu%s\n", |
863 |
p, p->next_free, p->attached_threads, |
864 |
p == result ? " *" : ""); |
865 |
write_message (buf); |
866 |
p = p->next; |
867 |
if (p == &main_arena) |
868 |
break; |
869 |
} |
870 |
abort (); |
871 |
} |
872 |
(void) mutex_unlock (&free_list_lock); |
873 |
} |
874 |
|
735 |
return result; |
875 |
return result; |
736 |
} |
876 |
} |
737 |
|
877 |
|
|
|
878 |
/* Remove the arena from the free list (if it is present). |
879 |
free_list_lock must have been acquired by the caller. */ |
880 |
static void |
881 |
remove_from_free_list (mstate arena) |
882 |
{ |
883 |
mstate *previous = &free_list; |
884 |
for (mstate p = free_list; p != NULL; p = p->next_free) |
885 |
{ |
886 |
assert (p->attached_threads == 0); |
887 |
if (p == arena) |
888 |
{ |
889 |
/* Remove the requested arena from the list. */ |
890 |
*previous = p->next_free; |
891 |
break; |
892 |
} |
893 |
else |
894 |
previous = &p->next_free; |
895 |
} |
896 |
} |
897 |
|
738 |
/* Lock and return an arena that can be reused for memory allocation. |
898 |
/* Lock and return an arena that can be reused for memory allocation. |
739 |
Avoid AVOID_ARENA as we have already failed to allocate memory in |
899 |
Avoid AVOID_ARENA as we have already failed to allocate memory in |
740 |
it and it is currently locked. */ |
900 |
it and it is currently locked. */ |
Lines 782-796
reused_arena (mstate avoid_arena)
Link Here
|
782 |
(void) mutex_lock (&result->mutex); |
942 |
(void) mutex_lock (&result->mutex); |
783 |
|
943 |
|
784 |
out: |
944 |
out: |
785 |
/* Attach the arena to the current thread. Note that we may have |
945 |
/* Attach the arena to the current thread. */ |
786 |
selected an arena which was on free_list. */ |
|
|
787 |
{ |
946 |
{ |
788 |
/* Update the arena thread attachment counters. */ |
947 |
/* Update the arena thread attachment counters. */ |
|
|
948 |
check_free_list (__func__, "before detach"); |
789 |
mstate replaced_arena = thread_arena; |
949 |
mstate replaced_arena = thread_arena; |
790 |
(void) mutex_lock (&free_list_lock); |
950 |
(void) mutex_lock (&free_list_lock); |
791 |
detach_arena (replaced_arena); |
951 |
detach_arena (replaced_arena); |
|
|
952 |
|
953 |
/* We may have picked up an arena on the free list. We need to |
954 |
preserve the invariant that no arena on the free list has a |
955 |
positive attached_threads counter (otherwise, |
956 |
arena_thread_freeres cannot use the counter to determine if the |
957 |
arena needs to be put on the free list). We unconditionally |
958 |
remove the selected arena from the free list. The caller of |
959 |
reused_arena checked the free list and observed it to be empty, |
960 |
so the list is very short. */ |
961 |
remove_from_free_list (result); |
962 |
|
792 |
++result->attached_threads; |
963 |
++result->attached_threads; |
|
|
964 |
|
793 |
(void) mutex_unlock (&free_list_lock); |
965 |
(void) mutex_unlock (&free_list_lock); |
|
|
966 |
check_free_list (__func__, "after detach"); |
794 |
} |
967 |
} |
795 |
|
968 |
|
796 |
LIBC_PROBE (memory_arena_reuse, 2, result, avoid_arena); |
969 |
LIBC_PROBE (memory_arena_reuse, 2, result, avoid_arena); |
Lines 804-809
static mstate
Link Here
|
804 |
internal_function |
977 |
internal_function |
805 |
arena_get2 (size_t size, mstate avoid_arena) |
978 |
arena_get2 (size_t size, mstate avoid_arena) |
806 |
{ |
979 |
{ |
|
|
980 |
check_attachment (); \ |
807 |
mstate a; |
981 |
mstate a; |
808 |
|
982 |
|
809 |
static size_t narenas_limit; |
983 |
static size_t narenas_limit; |
Lines 848-853
arena_get2 (size_t size, mstate avoid_arena)
Link Here
|
848 |
else |
1022 |
else |
849 |
a = reused_arena (avoid_arena); |
1023 |
a = reused_arena (avoid_arena); |
850 |
} |
1024 |
} |
|
|
1025 |
check_attachment (); \ |
851 |
return a; |
1026 |
return a; |
852 |
} |
1027 |
} |
853 |
|
1028 |
|
Lines 887-901
arena_thread_freeres (void)
Link Here
|
887 |
if (a != NULL) |
1062 |
if (a != NULL) |
888 |
{ |
1063 |
{ |
889 |
(void) mutex_lock (&free_list_lock); |
1064 |
(void) mutex_lock (&free_list_lock); |
|
|
1065 |
check_free_list_nolock (__func__, "before detach"); |
890 |
/* If this was the last attached thread for this arena, put the |
1066 |
/* If this was the last attached thread for this arena, put the |
891 |
arena on the free list. */ |
1067 |
arena on the free list. */ |
892 |
assert (a->attached_threads > 0); |
1068 |
assert (a->attached_threads > 0); |
893 |
if (--a->attached_threads == 0) |
1069 |
if (--a->attached_threads == 0) |
894 |
{ |
1070 |
{ |
|
|
1071 |
for (mstate p = free_list; p != NULL; p = p->next_free) |
1072 |
if (p == a) |
1073 |
{ |
1074 |
char buf[256]; |
1075 |
__snprintf (buf, sizeof (buf), |
1076 |
"Pushing %p to the free list creates a loop\n", a); |
1077 |
write_message (buf); |
1078 |
for (mstate p = free_list; p != NULL; p = p->next_free) |
1079 |
{ |
1080 |
__snprintf (buf, sizeof (buf), " %p %zu%s\n", |
1081 |
p, p->attached_threads, |
1082 |
p == a ? " *" : ""); |
1083 |
write_message (buf); |
1084 |
} |
1085 |
|
1086 |
write_message ("Arenas:\n"); |
1087 |
size_t arena_number = 0; |
1088 |
for (mstate p = &main_arena; ; ) |
1089 |
{ |
1090 |
__snprintf (buf, sizeof (buf), " (%zu) %p (next_free: %p) %zu%s\n", |
1091 |
arena_number++, p, p->next_free, p->attached_threads, |
1092 |
p == a ? " *" : ""); |
1093 |
write_message (buf); |
1094 |
p = p->next; |
1095 |
if (p == &main_arena) |
1096 |
break; |
1097 |
} |
1098 |
abort (); |
1099 |
} |
895 |
a->next_free = free_list; |
1100 |
a->next_free = free_list; |
896 |
free_list = a; |
1101 |
free_list = a; |
897 |
} |
1102 |
} |
898 |
(void) mutex_unlock (&free_list_lock); |
1103 |
(void) mutex_unlock (&free_list_lock); |
|
|
1104 |
check_free_list (__func__, "after detach"); |
899 |
} |
1105 |
} |
900 |
} |
1106 |
} |
901 |
text_set_element (__libc_thread_subfreeres, arena_thread_freeres); |
1107 |
text_set_element (__libc_thread_subfreeres, arena_thread_freeres); |