2021-03-09 01:16:23 +01:00
|
|
|
#+TITLE: Memory management
|
|
|
|
#+SETUPFILE: ../docs/theme.setup
|
2020-10-22 01:24:14 +02:00
|
|
|
|
2021-03-09 01:16:23 +01:00
|
|
|
We override the allocation functions to enable the possibility of
|
|
|
|
optimized libraries to fine-tune the memory allocation.
|
2020-10-16 23:56:22 +02:00
|
|
|
|
|
|
|
|
2021-03-09 01:16:23 +01:00
|
|
|
* Headers :noexport:
|
|
|
|
|
|
|
|
#+NAME: filename
|
|
|
|
#+begin_src elisp tangle: no
|
|
|
|
(file-name-nondirectory (substring buffer-file-name 0 -4))
|
|
|
|
#+end_src
|
2020-10-16 23:56:22 +02:00
|
|
|
|
2021-03-09 01:16:23 +01:00
|
|
|
#+begin_src c :tangle (eval c)
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdlib.h>
|
2021-03-10 12:58:38 +01:00
|
|
|
#include <assert.h>
|
|
|
|
|
2021-03-09 01:16:23 +01:00
|
|
|
#include "qmckl_error.h"
|
|
|
|
#include "qmckl_context.h"
|
2021-03-10 12:58:38 +01:00
|
|
|
#include "qmckl_context_private.h"
|
2021-03-09 01:16:23 +01:00
|
|
|
#include "qmckl_memory.h"
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
#+begin_src c :tangle (eval c_test) :noweb yes
|
2020-10-17 01:10:54 +02:00
|
|
|
#include "qmckl.h"
|
|
|
|
#include "munit.h"
|
2021-03-09 01:16:23 +01:00
|
|
|
MunitResult test_<<filename()>>() {
|
|
|
|
#+end_src
|
2020-10-16 23:56:22 +02:00
|
|
|
|
2021-03-10 12:58:38 +01:00
|
|
|
*
|
2021-03-18 23:55:50 +01:00
|
|
|
:PROPERTIES:
|
|
|
|
:UNNUMBERED: t
|
|
|
|
:END:
|
|
|
|
|
2021-03-10 12:58:38 +01:00
|
|
|
Memory allocation inside the library should be done with
|
|
|
|
~qmckl_malloc~. It lets the library choose how the memory will be
|
|
|
|
allocated, and a pointer is returned to the user. The context is
|
|
|
|
passed to let the library store data related to the allocation
|
|
|
|
inside the context. In this particular implementation of the library,
|
|
|
|
we store a list of allocated pointers so that all the memory can be
|
|
|
|
properly freed when the library is de-initialized.
|
|
|
|
If the allocation failed, the ~NULL~ pointer is returned.
|
|
|
|
|
|
|
|
# Header
|
|
|
|
#+begin_src c :tangle (eval h) :noexport
|
|
|
|
void* qmckl_malloc(qmckl_context context,
|
2021-03-09 01:16:23 +01:00
|
|
|
const size_t size);
|
|
|
|
#+end_src
|
2021-03-10 12:58:38 +01:00
|
|
|
|
2021-03-20 16:56:22 +01:00
|
|
|
In this implementation, we use ~calloc~ because it initializes the
|
|
|
|
memory block to zero, so structs will have ~NULL~-initialized pointers.
|
|
|
|
|
2021-03-10 12:58:38 +01:00
|
|
|
# Source
|
|
|
|
#+begin_src c :tangle (eval c)
|
|
|
|
void* qmckl_malloc(qmckl_context context, const size_t size) {
|
2020-10-16 23:56:22 +02:00
|
|
|
|
2021-03-20 16:56:22 +01:00
|
|
|
void * pointer = calloc(size, (size_t) 1);
|
2021-03-10 12:58:38 +01:00
|
|
|
|
|
|
|
if (qmckl_context_check(context) != QMCKL_NULL_CONTEXT) {
|
|
|
|
qmckl_exit_code rc;
|
|
|
|
rc = qmckl_context_append_memory(context, pointer, size);
|
|
|
|
assert (rc == QMCKL_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
return pointer;
|
|
|
|
}
|
|
|
|
#+end_src
|
2021-03-18 23:55:50 +01:00
|
|
|
|
2021-03-10 12:58:38 +01:00
|
|
|
# Fortran interface
|
|
|
|
#+begin_src f90 :tangle (eval fh) :noexport
|
2020-11-05 15:27:25 +01:00
|
|
|
interface
|
|
|
|
type (c_ptr) function qmckl_malloc (context, size) bind(C)
|
|
|
|
use, intrinsic :: iso_c_binding
|
|
|
|
integer (c_int64_t), intent(in), value :: context
|
|
|
|
integer (c_int64_t), intent(in), value :: size
|
|
|
|
end function qmckl_malloc
|
|
|
|
end interface
|
2021-03-09 01:16:23 +01:00
|
|
|
#+end_src
|
|
|
|
|
2021-03-18 23:55:50 +01:00
|
|
|
# Test :noexport:
|
2021-03-09 01:16:23 +01:00
|
|
|
#+begin_src c :tangle (eval c_test)
|
2021-03-18 23:55:50 +01:00
|
|
|
qmckl_context context = qmckl_context_create();
|
2021-03-09 01:16:23 +01:00
|
|
|
|
2021-03-18 23:55:50 +01:00
|
|
|
int *a = (int*) qmckl_malloc(context, 3*sizeof(int));
|
|
|
|
munit_assert(a != NULL);
|
|
|
|
|
|
|
|
a[0] = 1; munit_assert_int(a[0], ==, 1);
|
|
|
|
a[1] = 2; munit_assert_int(a[1], ==, 2);
|
|
|
|
a[2] = 3; munit_assert_int(a[2], ==, 3);
|
|
|
|
#+end_src
|
2021-03-09 01:16:23 +01:00
|
|
|
|
2021-03-18 23:55:50 +01:00
|
|
|
When freeing the memory with ~qmckl_free~, the context is passed, in
|
|
|
|
case some important information has been stored related to memory
|
|
|
|
allocation and needs to be updated.
|
2021-03-09 01:16:23 +01:00
|
|
|
|
|
|
|
#+begin_src c :tangle (eval h)
|
|
|
|
qmckl_exit_code qmckl_free(qmckl_context context,
|
|
|
|
void *ptr);
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
#+begin_src f90 :tangle (eval fh)
|
2020-11-05 15:27:25 +01:00
|
|
|
interface
|
2021-03-05 03:45:30 +01:00
|
|
|
integer (c_int32_t) function qmckl_free (context, ptr) bind(C)
|
2020-11-05 15:27:25 +01:00
|
|
|
use, intrinsic :: iso_c_binding
|
2021-03-05 03:45:30 +01:00
|
|
|
integer (c_int64_t), intent(in), value :: context
|
2020-11-05 15:27:25 +01:00
|
|
|
type (c_ptr), intent(in), value :: ptr
|
2021-02-19 01:39:42 +01:00
|
|
|
end function qmckl_free
|
2020-11-05 15:27:25 +01:00
|
|
|
end interface
|
2021-03-09 01:16:23 +01:00
|
|
|
#+end_src
|
2021-03-05 03:45:30 +01:00
|
|
|
|
2021-03-18 23:55:50 +01:00
|
|
|
# Source
|
2021-03-09 01:16:23 +01:00
|
|
|
#+begin_src c :tangle (eval c)
|
2021-03-05 03:45:30 +01:00
|
|
|
qmckl_exit_code qmckl_free(qmckl_context context, void *ptr) {
|
2021-03-10 12:58:38 +01:00
|
|
|
if (qmckl_context_check(context) != QMCKL_NULL_CONTEXT) {
|
|
|
|
|
|
|
|
if (ptr == NULL) {
|
|
|
|
return qmckl_failwith(context,
|
|
|
|
QMCKL_INVALID_ARG_2,
|
|
|
|
"qmckl_free",
|
|
|
|
"NULL pointer");
|
|
|
|
}
|
|
|
|
|
|
|
|
qmckl_exit_code rc;
|
|
|
|
rc = qmckl_context_remove_memory(context, ptr);
|
|
|
|
|
|
|
|
assert (rc == QMCKL_SUCCESS);
|
|
|
|
}
|
2020-10-16 23:56:22 +02:00
|
|
|
free(ptr);
|
2021-03-05 03:45:30 +01:00
|
|
|
return QMCKL_SUCCESS;
|
2020-10-16 23:56:22 +02:00
|
|
|
}
|
2021-03-09 01:16:23 +01:00
|
|
|
#+end_src
|
2020-10-22 01:24:14 +02:00
|
|
|
|
2021-03-18 23:55:50 +01:00
|
|
|
# Test
|
|
|
|
#+begin_src c :tangle (eval c_test) :exports none
|
2021-03-05 03:45:30 +01:00
|
|
|
qmckl_exit_code rc;
|
2021-03-18 23:55:50 +01:00
|
|
|
|
|
|
|
munit_assert(a != NULL);
|
|
|
|
rc = qmckl_free(context, a);
|
|
|
|
munit_assert(rc == QMCKL_SUCCESS);
|
|
|
|
|
|
|
|
rc = qmckl_context_destroy(context);
|
2021-03-05 03:45:30 +01:00
|
|
|
munit_assert(rc == QMCKL_SUCCESS);
|
2021-02-19 01:39:42 +01:00
|
|
|
|
2021-03-09 01:16:23 +01:00
|
|
|
#+end_src
|
2020-10-16 23:56:22 +02:00
|
|
|
|
2021-03-09 01:16:23 +01:00
|
|
|
* End of files :noexport:
|
2020-10-16 23:56:22 +02:00
|
|
|
|
2021-03-09 01:16:23 +01:00
|
|
|
** Test
|
|
|
|
#+begin_src c :comments org :tangle (eval c_test)
|
2020-10-17 01:10:54 +02:00
|
|
|
return MUNIT_OK;
|
2020-10-22 01:24:14 +02:00
|
|
|
}
|
2020-10-17 01:10:54 +02:00
|
|
|
|
2021-03-09 01:16:23 +01:00
|
|
|
#+end_src
|
2020-11-05 15:27:25 +01:00
|
|
|
|
|
|
|
|
2021-03-09 01:16:23 +01:00
|
|
|
# -*- mode: org -*-
|
|
|
|
# vim: syntax=c
|