2 * @copyright Copyright (c) 2016-2020 TOYOTA MOTOR CORPORATION.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 * @brief region manage
25 #include <native_service/cl_region.h>
28 #define cl_align_ptr(p, a) \
29 (uint8_t *) (((long)(p) + ((long)a - 1)) & ~((long)a - 1))
31 static void *cl_region_anonmmap(size_t size);
32 static void *cl_region_expand(cl_region_t *region, size_t size, size_t align_size);
33 static void *cl_region_alloc_large(cl_region_t *region, size_t size);
36 CL_RegionCreate(size_t size) {
40 pagesize = sysconf(_SC_PAGE_SIZE);
41 size = ((size + (size_t)pagesize - 1) / (size_t)pagesize) * (size_t)pagesize;
43 r = cl_region_anonmmap(size);
48 r->d.last = (uint8_t *) r + sizeof(cl_region_t);
49 r->d.end = (uint8_t *) r + size;
53 size = size - sizeof(cl_region_t);
54 r->max = (size < (pagesize - 1)) ? size : (size_t)(pagesize - 1);
65 CL_RegionDestroy(cl_region_t *region) {
68 cl_region_cleanup_t *c;
70 for (c = region->cleanup; c; c = c->next) {
72 CL_DBG_PRINT("run cleanup: %p\n", c->handler);
77 for (l = region->large; l; l = l->next) {
79 CL_DBG_PRINT("free: %p\n", l->alloc);
81 if (l->alloc) { // LCOV_EXCL_BR_LINE 6: double check, mmap in cl_monitor.c
82 if (munmap(l->alloc, l->size) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc munmap
83 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
84 CL_PERROR("munmap"); // LCOV_EXCL_LINE 5: fail safe for libc munmap
89 for (r = region, n = region->d.next; /* void */; r = n, n = n->d.next) {
90 if (munmap(r, (size_t)(r->d.end - (uint8_t *)r)) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for libc munmap
91 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
92 CL_PERROR("munmap"); // LCOV_EXCL_LINE 5: fail safe for libc munmap
103 cl_region_alloc(cl_region_t *region, size_t size, size_t align_size) {
105 volatile uint8_t *old_last;
108 if (size <= region->max) {
114 old_last = r->d.last;
115 m = cl_align_ptr(old_last, align_size);
116 if ((size_t)(r->d.end - m) >= size) {
117 if (false == __sync_bool_compare_and_swap(&r->d.last, old_last, m + size)) {
127 return cl_region_expand(region, size, align_size);
130 return cl_region_alloc_large(region, size);
135 cl_region_anonmmap(size_t size) {
138 p = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
139 if (p == MAP_FAILED) { /* pgr0203 */
149 cl_region_expand(cl_region_t *region, size_t size, size_t align_size) {
152 cl_region_t *r, *new, *current;
154 psize = (size_t)(region->d.end - (uint8_t *)region);
156 m = cl_region_anonmmap(psize);
157 if (m == NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for libc mmap
158 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
159 return NULL;// LCOV_EXCL_LINE 5: fail safe for libc mmap
162 new = (cl_region_t *)m;
164 new->d.end = m + psize;
168 m += sizeof(cl_region_data_t);
169 m = cl_align_ptr(m, align_size);
170 new->d.last = m + size;
172 current = region->current;
174 for (r = current; r->d.next; r = r->d.next) { /* pgr0689 */
175 if (r->d.failed++ > 4) {
180 while (false == __sync_bool_compare_and_swap(&r->d.next, NULL, new)) {
181 for (r = r->d.next; r->d.next; r = r->d.next) {} /* pgr0689 */
184 region->current = current ? current : new;
191 cl_region_alloc_large(cl_region_t *region, size_t size) {
195 cl_region_large_t *large;
197 pagesize = sysconf(_SC_PAGE_SIZE);
198 size = ((size + (size_t)pagesize - 1) / (size_t)pagesize) * (size_t)pagesize;
200 p = cl_region_anonmmap(size);
202 if (p == NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for libc mmap
203 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
204 return NULL;// LCOV_EXCL_LINE 5: fail safe for libc mmap
209 for (large = region->large; large; large = large->next) {
210 if (large->alloc == NULL) {
211 if (false == __sync_bool_compare_and_swap(&large->alloc, NULL, p)) {
223 large = CL_RegionAlloc(region, cl_region_large_t, 1);
224 if (large == NULL) { // LCOV_EXCL_START 5: fail safe for libc mmap
225 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
226 if (munmap(p, size) < 0) {
234 large->next = region->large;
235 while (false == __sync_bool_compare_and_swap(®ion->large, large->next, large)) { // LCOV_EXCL_BR_LINE 100: race condition // NOLINT (readability/nolint)
236 // LCOV_EXCL_START 100: race condition
237 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
238 large->next = region->large;
246 CL_RegionFree(cl_region_t *region, void *p) {
247 cl_region_large_t *l;
249 for (l = region->large; l; l = l->next) {
251 CL_DBG_PRINT("free: %p\n", l->alloc);
252 if (munmap(l->alloc, l->size) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for libc munmap
253 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
254 CL_PERROR("munmap");// LCOV_EXCL_LINE 5: fail safe for libc munmap
265 cl_region_cleanup_t *
266 cl_region_cleanup_add(cl_region_t *region, size_t size, size_t align_size) {
267 cl_region_cleanup_t *c;
269 c = CL_RegionAlloc(region, cl_region_cleanup_t, 1);
270 if (c == NULL) { // LCOV_EXCL_START 5: fail safe for libc mmap
271 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
276 c->data = cl_region_alloc(region, size, align_size);
277 if (c->data == NULL) { // LCOV_EXCL_START 5: fail safe for libc mmap
278 AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
286 c->next = region->cleanup;
290 CL_DBG_PRINT("add cleanup: %p\n", c);
295 /* vim:set ts=8 sw=2 sts=2: */