• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *    http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 
17 #include <stdio.h>
18 #include <malloc.h>
19 #include <stdlib.h>
20 #include <pthread.h>
21 #include <stdint.h>
22 #include <memory.h>
23 
24 #include "test-malloc-api-common.h"
25 
26 #define BARRIER_HEIGHT 2
27 #define ALLOCATIONS_NUMBER 8
28 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
29 
30 typedef struct iterate_arg_s {
31 	uintptr_t allocs[ALLOCATIONS_NUMBER];
32 	size_t allocs_reported_number[ALLOCATIONS_NUMBER];
33 	size_t allocs_actual_sizes[ALLOCATIONS_NUMBER];
34 	size_t reported_sizes[ALLOCATIONS_NUMBER];
35 } iterate_arg_t;
36 
37 typedef struct {
38 	uintptr_t *base;
39 	size_t size;
40 } allocations_info_t;
41 
42 static const size_t allocs_sizes[ALLOCATIONS_NUMBER] = {
43 	8,
44 	2 * 1024,
45 	64 * 1024,
46 	512 * 1024,
47 	2 * 1024 * 1024,
48 	8 * 1024 * 1024,
49 	16 * 1024 * 1024,
50 	32 * 1024 * 1024
51 };
52 
iterate_callback(void * base,size_t size,void * data)53 void iterate_callback(void *base, size_t size, void *data)
54 {
55 	iterate_arg_t *iterate_arg = (iterate_arg_t *) data;
56 	uintptr_t end;
57 	if (__builtin_add_overflow((uintptr_t) base, size, &end)) {
58 		return;
59 	}
60 
61 	for (size_t i = 0; i < ALLOCATIONS_NUMBER; ++i) {
62 		if (iterate_arg->allocs[i] >= (uintptr_t) base && iterate_arg->allocs[i] < end) {
63 			iterate_arg->allocs_reported_number[i]++;
64 			uintptr_t max_size = end - iterate_arg->allocs[i];
65 			iterate_arg->reported_sizes[i] = MIN(size, max_size);
66 		}
67 	}
68 }
69 
fill_allocations_info(const iterate_arg_t * iterate_arg,allocations_info_t * allocations_info)70 void fill_allocations_info(const iterate_arg_t *iterate_arg, allocations_info_t *allocations_info)
71 {
72 	size_t min_idx, max_idx;
73 	uintptr_t min_val = UINTPTR_MAX, max_val = 0;
74 
75 	const uintptr_t *allocs = iterate_arg->allocs;
76 
77 	for (size_t i = 0; i < ALLOCATIONS_NUMBER; ++i) {
78 		if (allocs[i] > max_val) {
79 			max_val = allocs[i];
80 			max_idx = i;
81 		}
82 		if (allocs[i] < min_val) {
83 			min_val = allocs[i];
84 			min_idx = i;
85 		}
86 	}
87 
88 	allocations_info->base = (void *) allocs[min_idx];
89 	allocations_info->size = allocs[max_idx] - allocs[min_idx] + allocs_sizes[max_idx];
90 }
91 
make_allocations(iterate_arg_t * iterate_arg)92 void make_allocations(iterate_arg_t *iterate_arg)
93 {
94 	uintptr_t *allocs = iterate_arg->allocs;
95 	size_t *allocs_actual_sizes = iterate_arg->allocs_actual_sizes;
96 
97 	for (size_t i = 0; i < ALLOCATIONS_NUMBER; ++i) {
98 		allocs[i] = (uintptr_t) malloc(allocs_sizes[i]);
99 		allocs_actual_sizes[i] = malloc_usable_size((void *) allocs[i]);
100 	}
101 }
102 
free_allocations(iterate_arg_t * iterate_arg)103 void free_allocations(iterate_arg_t *iterate_arg)
104 {
105 	uintptr_t *allocs = iterate_arg->allocs;
106 
107 	for (size_t i = 0; i < ALLOCATIONS_NUMBER; ++i) {
108 		free((void *) allocs[i]);
109 	}
110 }
111 
iterate_wrapper(iterate_arg_t * iterate_arg)112 int iterate_wrapper(iterate_arg_t *iterate_arg)
113 {
114 	int ret = 0;
115 	allocations_info_t allocations_info;
116 	fill_allocations_info(iterate_arg, &allocations_info);
117 	malloc_iterate(allocations_info.base, allocations_info.size, iterate_callback, iterate_arg);
118 
119 	for (size_t i = 0; i < ALLOCATIONS_NUMBER; ++i) {
120 		if (iterate_arg->allocs_reported_number[i] != 1) {
121 			ret = -1;
122 		}
123 	}
124 	return ret;
125 }
126 
127 pthread_barrier_t routine_allocated;
128 pthread_barrier_t routine_iterated;
129 
allocate_routine(void * vargp)130 void *allocate_routine(void *vargp)
131 {
132 	iterate_arg_t *iterate_arg = (iterate_arg_t *) vargp;
133 	make_allocations(iterate_arg);
134 	pthread_barrier_wait(&routine_allocated);
135 	pthread_barrier_wait(&routine_iterated);
136 	return NULL;
137 }
138 
abandoned_allocate_routine(void * vargp)139 void *abandoned_allocate_routine(void *vargp)
140 {
141 	iterate_arg_t *iterate_arg = (iterate_arg_t *) vargp;
142 	make_allocations(iterate_arg);
143 	return NULL;
144 }
145 
test_iterate_main_thread(void)146 int test_iterate_main_thread(void)
147 {
148 	int ret;
149 	iterate_arg_t iterate_arg = {{0}, {0}, {0}, {0}};
150 	make_allocations(&iterate_arg);
151 	ret = iterate_wrapper(&iterate_arg);
152 	free_allocations(&iterate_arg);
153 	return ret;
154 }
155 
test_iterate_another_thread(void)156 int test_iterate_another_thread(void)
157 {
158 	int ret;
159 	iterate_arg_t iterate_arg_routine = {{0}, {0}, {0}, {0}};
160 	pthread_barrier_init(&routine_allocated, NULL, BARRIER_HEIGHT);
161 	pthread_barrier_init(&routine_iterated, NULL, BARRIER_HEIGHT);
162 	pthread_t thread_id;
163 	pthread_create(&thread_id, NULL, allocate_routine, (void *) &iterate_arg_routine);
164 	pthread_barrier_wait(&routine_allocated);
165 	ret = iterate_wrapper(&iterate_arg_routine);
166 	free_allocations(&iterate_arg_routine);
167 	pthread_barrier_wait(&routine_iterated);
168 	return ret;
169 }
170 
test_iterate_over_abandoned_allocs(void)171 int test_iterate_over_abandoned_allocs(void)
172 {
173 	int ret;
174 	iterate_arg_t iterate_arg_routine = {{0}, {0}, {0}, {0}};
175 	pthread_t thread_id;
176 	pthread_create(&thread_id, NULL, abandoned_allocate_routine, (void *) &iterate_arg_routine);
177 	pthread_join(thread_id, NULL);
178 	ret = iterate_wrapper(&iterate_arg_routine);
179 	free_allocations(&iterate_arg_routine);
180 	return ret;
181 }
182 
main()183 int main()
184 {
185 	int ret = 0;
186 
187 	ret = check_and_report("Testing iterate main thread", test_iterate_main_thread);
188 
189 	ret = -(ret || check_and_report("Testing iterate another thread", test_iterate_another_thread));
190 
191 	ret = -(ret || check_and_report("Testing iterate over abandoned allocations", test_iterate_over_abandoned_allocs));
192 
193 	return ret;
194 }
195