blob: 32da9b0fa0365f53ddb91bedb0b147d0afa874cd [file] [log] [blame]
/* 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);
}