| /* Copyright (C) 2025-2026 Free Software Foundation, Inc. |
| Contributed by Thomas Koenig, Nicolas Koenig, Andre Vehreschild |
| |
| This file is part of the GNU Fortran Shmem Coarray Library (caf_shmem). |
| |
| Caf_shmem is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| Caf_shmem is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| Under Section 7 of GPL version 3, you are granted additional |
| permissions described in the GCC Runtime Library Exception, version |
| 3.1, as published by the Free Software Foundation. |
| |
| You should have received a copy of the GNU General Public License and |
| a copy of the GCC Runtime Library Exception along with this program; |
| see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
| <http://www.gnu.org/licenses/>. */ |
| |
| /* Main allocation routine, works like malloc. Round up allocations |
| to the next power of two and keep free lists in buckets. */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include "libgfortran.h" |
| |
| #include "allocator.h" |
| #include "supervisor.h" |
| #include "thread_support.h" |
| |
| #include <assert.h> |
| |
| typedef struct |
| { |
| shared_mem_ptr next; |
| } bucket; |
| |
| size_t |
| alignto (size_t size, size_t align) |
| { |
| return align * ((size + align - 1) / align); |
| } |
| |
| size_t pagesize; |
| |
| size_t |
| round_to_pagesize (size_t s) |
| { |
| return alignto (s, pagesize); |
| } |
| |
| /* Initialize the allocator. */ |
| |
| void |
| allocator_init (allocator *a, allocator_shared *s, shared_memory sm) |
| { |
| *a = (allocator) {s, sm}; |
| } |
| |
| void |
| allocator_init_supervisor (allocator *a, allocator_shared *s, shared_memory sm) |
| { |
| *a = (allocator) {s, sm}; |
| initialize_shared_mutex (&s->lock); |
| for (size_t i = 0; i < VOIDP_BITS; i++) |
| s->free_bucket_head[i] = SHMPTR_NULL; |
| } |
| |
| #define MAX_ALIGN 16 |
| |
| static size_t |
| next_power_of_two (size_t size) |
| { |
| assert (size != 1); |
| return (size_t)1 << (__SIZEOF_LONG_LONG__ * __CHAR_BIT__ - __builtin_clzll (size - 1)); |
| } |
| |
| shared_mem_ptr |
| allocator_shared_malloc (allocator *a, size_t size) |
| { |
| shared_mem_ptr ret; |
| size_t sz; |
| size_t act_size; |
| int bucket_list_index; |
| |
| sz = next_power_of_two (size); |
| act_size = sz > sizeof (bucket) ? sz : sizeof (bucket); |
| bucket_list_index = __builtin_clzl (act_size); |
| assert (bucket_list_index |
| < (int) (sizeof (a->s->free_bucket_head) / sizeof (shared_mem_ptr))); |
| |
| if (SHMPTR_IS_NULL (a->s->free_bucket_head[bucket_list_index])) |
| return shared_memory_get_mem_with_alignment (a->shm, act_size, MAX_ALIGN); |
| |
| ret = a->s->free_bucket_head[bucket_list_index]; |
| a->s->free_bucket_head[bucket_list_index] |
| = (SHMPTR_AS (bucket *, ret, a->shm)->next); |
| return ret; |
| } |
| |
| /* Free memory. */ |
| |
| void |
| allocator_shared_free (allocator *a, shared_mem_ptr p, size_t size) |
| { |
| bucket *b; |
| size_t sz; |
| int bucket_list_index; |
| size_t act_size; |
| |
| sz = next_power_of_two (size); |
| act_size = sz > sizeof (bucket) ? sz : sizeof (bucket); |
| bucket_list_index = __builtin_clzl (act_size); |
| |
| b = SHMPTR_AS (bucket *, p, a->shm); |
| b->next = a->s->free_bucket_head[bucket_list_index]; |
| a->s->free_bucket_head[bucket_list_index] = p; |
| } |
| |
| void |
| allocator_lock (allocator *a) |
| { |
| caf_shmem_mutex_lock (&a->s->lock); |
| } |
| |
| void |
| allocator_unlock (allocator *a) |
| { |
| caf_shmem_mutex_unlock (&a->s->lock); |
| } |