1
0
mirror of https://github.com/TREX-CoE/qmckl.git synced 2024-11-09 07:33:59 +01:00
qmckl/org/qmckl_context.org

561 lines
15 KiB
Org Mode
Raw Normal View History

2021-03-09 01:16:23 +01:00
#+TITLE: Context
2021-04-30 01:26:19 +02:00
#+SETUPFILE: ../tools/theme.setup
#+INCLUDE: ../tools/lib.org
2020-10-14 00:52:50 +02:00
2021-03-09 01:16:23 +01:00
* Headers :noexport:
2021-03-05 03:45:30 +01:00
2021-03-09 01:16:23 +01:00
#+begin_src c :tangle (eval c_test) :noweb yes
#include "qmckl.h"
2021-05-11 16:41:03 +02:00
#include "assert.h"
2021-05-10 10:05:50 +02:00
#ifdef HAVE_CONFIG_H
2021-05-10 10:41:59 +02:00
#include "config.h"
2021-05-09 02:12:38 +02:00
#endif
2021-05-11 16:41:03 +02:00
int main() {
2021-03-09 01:16:23 +01:00
#+end_src
2021-03-05 03:45:30 +01:00
2021-03-30 14:51:23 +02:00
#+begin_src c :tangle (eval h_private_type) :noweb yes
#ifndef QMCKL_CONTEXT_HPT
#define QMCKL_CONTEXT_HPT
2021-03-05 03:45:30 +01:00
2021-05-10 10:05:50 +02:00
#ifdef HAVE_STDINT_H
2021-03-09 01:16:23 +01:00
#include <stdint.h>
2021-05-10 10:05:50 +02:00
#elif HAVE_INTTYPES_H
#include <inttypes.h>
#endif
2021-03-10 12:58:38 +01:00
#include <pthread.h>
2020-11-14 18:27:38 +01:00
2021-03-30 14:51:23 +02:00
#include "qmckl_error_private_type.h"
2021-03-30 22:40:56 +02:00
#include "qmckl_memory_private_type.h"
2021-03-30 14:51:23 +02:00
#include "qmckl_numprec_private_type.h"
2022-01-20 01:50:54 +01:00
#include "qmckl_point_private_type.h"
2021-05-16 00:53:17 +02:00
#include "qmckl_nucleus_private_type.h"
2021-04-21 01:56:47 +02:00
#include "qmckl_electron_private_type.h"
2021-04-01 01:19:33 +02:00
#include "qmckl_ao_private_type.h"
2021-09-15 18:30:41 +02:00
#include "qmckl_mo_private_type.h"
2023-03-30 17:07:11 +02:00
#include "qmckl_jastrow_champ_private_type.h"
#include "qmckl_determinant_private_type.h"
2021-10-11 16:06:23 +02:00
#include "qmckl_local_energy_private_type.h"
2022-01-20 01:50:54 +01:00
#include "qmckl_point_private_func.h"
2021-06-10 22:57:59 +02:00
#include "qmckl_nucleus_private_func.h"
#include "qmckl_electron_private_func.h"
#include "qmckl_ao_private_func.h"
2021-09-15 18:30:41 +02:00
#include "qmckl_mo_private_func.h"
2023-03-30 17:07:11 +02:00
#include "qmckl_jastrow_champ_private_func.h"
2021-10-04 16:52:13 +02:00
#include "qmckl_determinant_private_func.h"
2021-10-11 16:06:23 +02:00
#include "qmckl_local_energy_private_func.h"
2021-03-09 01:16:23 +01:00
#+end_src
2020-11-14 18:27:38 +01:00
2021-04-30 01:26:19 +02:00
#+begin_src c :tangle (eval c)
2021-05-10 10:05:50 +02:00
#ifdef HAVE_CONFIG_H
2021-05-10 10:41:59 +02:00
#include "config.h"
2021-05-09 02:12:38 +02:00
#endif
2021-05-10 10:05:50 +02:00
#ifdef HAVE_STDINT_H
2021-03-09 01:16:23 +01:00
#include <stdint.h>
2021-05-10 10:05:50 +02:00
#elif HAVE_INTTYPES_H
#include <inttypes.h>
#endif
2021-03-09 01:16:23 +01:00
#include <assert.h>
#include <math.h>
#include <stdlib.h>
2021-03-30 14:51:23 +02:00
#include <stdio.h>
2021-03-09 01:16:23 +01:00
#include <string.h>
2021-03-30 14:51:23 +02:00
#include <errno.h>
2022-02-25 13:57:13 +01:00
#include <pthread.h>
2020-11-14 18:27:38 +01:00
2021-05-11 13:57:23 +02:00
#include "qmckl.h"
2021-03-30 14:51:23 +02:00
#include "qmckl_context_private_type.h"
2021-03-30 22:40:56 +02:00
#include "qmckl_memory_private_func.h"
2021-03-30 14:51:23 +02:00
2021-03-09 01:16:23 +01:00
#+end_src
2022-02-25 13:57:13 +01:00
2021-03-09 01:16:23 +01:00
* Context handling
2020-11-14 18:27:38 +01:00
2021-03-30 14:51:23 +02:00
The context variable is a handle for the state of the library,
and is stored in a data structure which can't be seen outside of
the library. To simplify compatibility with other languages, the
pointer to the internal data structure is converted into a 64-bit
signed integer, defined in the ~qmckl_context~ type.
A value of ~QMCKL_NULL_CONTEXT~ for the context is equivalent to a
~NULL~ pointer.
#+NAME: qmckl_context
#+begin_src c :comments org :tangle (eval h_type)
typedef int64_t qmckl_context ;
#define QMCKL_NULL_CONTEXT (qmckl_context) 0
#+end_src
#+begin_src f90 :comments org :tangle (eval fh_type) :exports none
integer , parameter :: qmckl_context = c_int64_t
integer*8, parameter :: QMCKL_NULL_CONTEXT = 0
#+end_src
2021-04-30 01:26:19 +02:00
2021-03-30 14:51:23 +02:00
An immutable context would have required to implement a garbage
collector. To keep the library simple, we have chosen to implement
the context as a mutable data structure, so it has to be handled
with care.
2021-03-05 03:45:30 +01:00
2021-03-10 12:58:38 +01:00
By convention, in this file ~context~ is a ~qmckl_context~ variable
and ~ctx~ is a ~qmckl_context_struct*~ pointer.
2020-11-05 15:27:25 +01:00
2021-03-10 12:58:38 +01:00
** Data structure
2021-04-30 01:26:19 +02:00
2021-03-30 14:51:23 +02:00
#+begin_src c :comments org :tangle (eval h_private_type) :noweb yes :exports none
2020-10-16 13:58:05 +02:00
typedef struct qmckl_context_struct {
2021-03-30 14:51:23 +02:00
/* -- State of the library -- */
2020-11-14 18:27:38 +01:00
2021-03-30 14:51:23 +02:00
/* Validity checking */
uint64_t tag;
2020-11-14 18:27:38 +01:00
/* Numerical precision */
2021-03-30 14:51:23 +02:00
qmckl_numprec_struct numprec;
/* Thread lock */
int lock_count;
pthread_mutex_t mutex;
2020-11-14 18:27:38 +01:00
2021-03-05 03:45:30 +01:00
/* Error handling */
2021-03-30 14:51:23 +02:00
qmckl_error_struct error;
2021-03-10 12:58:38 +01:00
/* Memory allocation */
2021-03-30 14:51:23 +02:00
qmckl_memory_struct memory;
2021-03-10 12:58:38 +01:00
2021-04-21 01:56:47 +02:00
/* Current date */
uint64_t date;
2022-01-20 01:50:54 +01:00
/* Points */
2022-01-26 17:06:51 +01:00
qmckl_point_struct point;
2022-01-20 01:50:54 +01:00
2021-03-30 14:51:23 +02:00
/* -- Molecular system -- */
2023-03-30 17:07:11 +02:00
qmckl_nucleus_struct nucleus;
qmckl_electron_struct electron;
qmckl_ao_basis_struct ao_basis;
qmckl_mo_basis_struct mo_basis;
qmckl_jastrow_champ_struct jastrow_champ;
qmckl_determinant_struct det;
qmckl_local_energy_struct local_energy;
2021-03-10 12:58:38 +01:00
2021-04-01 01:19:33 +02:00
/* To be implemented:
2021-03-30 14:51:23 +02:00
,*/
2021-03-05 03:45:30 +01:00
2022-11-24 15:21:32 +01:00
/* Pointer to implementation-specific data */
void* qmckl_extra;
2020-10-14 00:52:50 +02:00
} qmckl_context_struct;
2021-03-10 12:58:38 +01:00
#+end_src
2022-11-24 15:21:32 +01:00
The qmckl_extra pointer lets the other implementation of the library
add specific things to the context. For example a GPU implementation
of QMCkl will need to store the device ID in the context, and this
can be made by creating a private data structure containing all
GPU-specific data, including the device ID.
2021-03-10 12:58:38 +01:00
A tag is used internally to check if the memory domain pointed
by a pointer is a valid context. This allows to check that even if
the pointer associated with a context is non-null, we can still
verify that it points to the expected data structure.
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval h_private_type) :noweb yes :exports none
#define VALID_TAG 0xBEEFFACE
#define INVALID_TAG 0xDEADBEEF
2021-03-10 12:58:38 +01:00
#+end_src
2021-03-05 03:45:30 +01:00
2021-03-10 12:58:38 +01:00
The ~qmckl_context_check~ function checks if the domain pointed by
the pointer is a valid context. It returns the input ~qmckl_context~
if the context is valid, ~QMCKL_NULL_CONTEXT~ otherwise.
2021-03-05 03:45:30 +01:00
2021-03-30 14:51:23 +02:00
#+begin_src c :comments org :tangle (eval h_func) :noexport
2022-02-24 19:06:19 +01:00
qmckl_context
qmckl_context_check (const qmckl_context context) ;
2021-03-09 01:16:23 +01:00
#+end_src
2020-10-22 00:50:07 +02:00
2022-02-24 19:06:19 +01:00
#+begin_src c :tangle (eval c) :exports none
2020-10-22 00:50:07 +02:00
qmckl_context qmckl_context_check(const qmckl_context context) {
2021-03-10 12:58:38 +01:00
if (context == QMCKL_NULL_CONTEXT)
return QMCKL_NULL_CONTEXT;
2020-10-14 00:52:50 +02:00
2022-04-05 11:03:38 +02:00
const qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
2020-11-05 00:46:19 +01:00
2021-03-18 18:02:06 +01:00
/* Try to access memory */
if (ctx->tag != VALID_TAG) {
return QMCKL_NULL_CONTEXT;
}
2020-10-22 00:50:07 +02:00
return context;
}
2021-03-10 12:58:38 +01:00
#+end_src
2020-10-14 00:52:50 +02:00
2022-02-24 19:06:19 +01:00
The context keeps a /date/ that allows to check which data needs
to be recomputed. The date is incremented when the context is touched.
When a new element is added to the context, the functions
2022-02-24 19:06:19 +01:00
[[Creation][=qmckl_context_create=]] [[Destroy][=qmckl_context_destroy=]] and [[Copy][=qmckl_context_copy=]]
should be updated in order to make deep copies.
2022-02-24 19:06:19 +01:00
When the electron coordinates have changed, the context is touched
2022-02-25 13:57:13 +01:00
using the following function.
2022-02-24 19:06:19 +01:00
2022-02-25 13:57:13 +01:00
#+begin_src c :comments org :tangle (eval h_func)
2022-02-24 19:06:19 +01:00
qmckl_exit_code
qmckl_context_touch (const qmckl_context context);
#+end_src
2022-02-24 19:06:19 +01:00
This has the effect to increment the date of the context.
#+begin_src c :tangle (eval c) :exports none
qmckl_exit_code
qmckl_context_touch(const qmckl_context context)
{
if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) {
return qmckl_failwith( context,
QMCKL_INVALID_CONTEXT,
"qmckl_context_touch",
NULL);
}
2022-04-04 12:11:26 +02:00
qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
2023-03-31 19:20:25 +02:00
ctx->electron.walker_old = ctx->electron.walker;
ctx->date += 1UL;
2022-08-07 14:57:10 +02:00
ctx->point.date = ctx-> date;
return QMCKL_SUCCESS;
}
#+end_src
2021-03-10 12:58:38 +01:00
** Creation
2021-04-30 01:26:19 +02:00
2021-03-10 12:58:38 +01:00
To create a new context, ~qmckl_context_create()~ should be used.
- Upon success, it returns a pointer to a new context with the ~qmckl_context~ type
- It returns ~QMCKL_NULL_CONTEXT~ upon failure to allocate the internal data structure
- A new context always has all its members initialized with a NULL value
2021-03-10 12:58:38 +01:00
# Header
2022-02-25 13:57:13 +01:00
#+begin_src c :comments org :tangle (eval h_func)
2020-10-14 00:52:50 +02:00
qmckl_context qmckl_context_create();
2021-03-10 12:58:38 +01:00
#+end_src
2020-10-14 00:52:50 +02:00
2021-03-10 12:58:38 +01:00
# Source
2022-02-24 19:06:19 +01:00
#+begin_src c :tangle (eval c) :exports none
2020-10-14 00:52:50 +02:00
qmckl_context qmckl_context_create() {
2021-03-30 14:51:23 +02:00
qmckl_context_struct* const ctx =
2022-04-04 12:11:26 +02:00
(qmckl_context_struct*) malloc (sizeof(qmckl_context_struct));
2021-03-10 12:58:38 +01:00
if (ctx == NULL) {
return QMCKL_NULL_CONTEXT;
2020-10-14 00:52:50 +02:00
}
2021-03-30 22:40:56 +02:00
/* Set all pointers and values to NULL */
{
memset(ctx, 0, sizeof(qmckl_context_struct));
}
2021-03-10 12:58:38 +01:00
/* Initialize lock */
2021-03-30 22:40:56 +02:00
{
pthread_mutexattr_t attr;
int rc;
2021-04-30 01:26:19 +02:00
rc = pthread_mutexattr_init(&attr);
2021-03-30 22:40:56 +02:00
assert (rc == 0);
2021-04-30 01:26:19 +02:00
2022-02-25 13:57:13 +01:00
#ifdef PTHREAD_MUTEX_RECURSIVE
2021-03-30 22:40:56 +02:00
(void) pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
2022-02-25 13:57:13 +01:00
#endif
2021-04-30 01:26:19 +02:00
2021-03-30 22:40:56 +02:00
rc = pthread_mutex_init ( &(ctx->mutex), &attr);
assert (rc == 0);
2021-04-30 01:26:19 +02:00
2021-03-30 22:40:56 +02:00
(void) pthread_mutexattr_destroy(&attr);
2021-04-30 01:26:19 +02:00
}
2021-03-10 12:58:38 +01:00
/* Initialize data */
2021-06-10 22:57:59 +02:00
{
ctx->tag = VALID_TAG;
2022-02-25 13:57:13 +01:00
2022-04-05 11:03:38 +02:00
const qmckl_context context = (qmckl_context) ctx;
2021-06-10 22:57:59 +02:00
assert ( qmckl_context_check(context) != QMCKL_NULL_CONTEXT );
2022-02-25 13:57:13 +01:00
2021-06-10 22:57:59 +02:00
qmckl_exit_code rc;
2022-02-25 13:57:13 +01:00
2021-06-10 22:57:59 +02:00
ctx->numprec.precision = QMCKL_DEFAULT_PRECISION;
ctx->numprec.range = QMCKL_DEFAULT_RANGE;
2022-01-20 01:50:54 +01:00
rc = qmckl_init_point(context);
assert (rc == QMCKL_SUCCESS);
2022-02-25 13:57:13 +01:00
2021-06-10 22:57:59 +02:00
rc = qmckl_init_electron(context);
assert (rc == QMCKL_SUCCESS);
2022-02-25 13:57:13 +01:00
2021-06-10 22:57:59 +02:00
rc = qmckl_init_nucleus(context);
assert (rc == QMCKL_SUCCESS);
2022-02-25 13:57:13 +01:00
2021-06-10 22:57:59 +02:00
rc = qmckl_init_ao_basis(context);
assert (rc == QMCKL_SUCCESS);
2022-02-25 13:57:13 +01:00
rc = qmckl_init_mo_basis(context);
assert (rc == QMCKL_SUCCESS);
2022-02-25 13:57:13 +01:00
rc = qmckl_init_determinant(context);
assert (rc == QMCKL_SUCCESS);
2023-03-30 17:07:11 +02:00
rc = qmckl_init_jastrow_champ(context);
assert (rc == QMCKL_SUCCESS);
2021-06-10 22:57:59 +02:00
}
2021-04-01 01:19:33 +02:00
2021-03-30 22:40:56 +02:00
/* Allocate qmckl_memory_struct */
{
const size_t size = 128L;
qmckl_memory_info_struct * new_array = calloc(size, sizeof(qmckl_memory_info_struct));
if (new_array == NULL) {
2021-03-31 01:52:43 +02:00
free(ctx);
2021-04-30 01:26:19 +02:00
return QMCKL_NULL_CONTEXT;
2021-03-30 22:40:56 +02:00
}
memset( &(new_array[0]), 0, size * sizeof(qmckl_memory_info_struct) );
2021-04-30 01:26:19 +02:00
2021-03-30 22:40:56 +02:00
ctx->memory.element = new_array;
ctx->memory.array_size = size;
ctx->memory.n_allocated = (size_t) 0;
}
2021-04-30 01:26:19 +02:00
2021-03-30 22:40:56 +02:00
return (qmckl_context) ctx;
2020-10-14 00:52:50 +02:00
}
2021-03-10 12:58:38 +01:00
#+end_src
2020-10-22 00:50:07 +02:00
2021-03-10 12:58:38 +01:00
# Fortran interface
2021-03-30 14:51:23 +02:00
#+begin_src f90 :tangle (eval fh_func) :exports none
2020-11-05 00:46:19 +01:00
interface
2021-03-30 14:51:23 +02:00
integer (qmckl_context) function qmckl_context_create() bind(C)
2020-11-05 00:46:19 +01:00
use, intrinsic :: iso_c_binding
2021-03-30 14:51:23 +02:00
import
2020-11-05 00:46:19 +01:00
end function qmckl_context_create
end interface
2021-03-10 12:58:38 +01:00
#+end_src
# Test
#+begin_src c :comments link :tangle (eval c_test) :exports none
2021-05-11 16:41:03 +02:00
assert( qmckl_context_check(QMCKL_NULL_CONTEXT) == QMCKL_NULL_CONTEXT);
2020-11-05 00:46:19 +01:00
2021-03-09 01:16:23 +01:00
qmckl_context context = qmckl_context_create();
2021-05-11 16:41:03 +02:00
assert( context != QMCKL_NULL_CONTEXT );
assert( qmckl_context_check(context) == context );
2021-03-10 12:58:38 +01:00
#+end_src
2020-10-14 01:43:13 +02:00
2021-03-10 12:58:38 +01:00
** Locking
2020-10-14 00:52:50 +02:00
2021-03-10 12:58:38 +01:00
For thread safety, the context may be locked/unlocked. The lock is
2021-03-18 18:02:06 +01:00
initialized with the ~PTHREAD_MUTEX_RECURSIVE~ attribute, and the
number of times the thread has locked it is saved in the
~lock_count~ attribute.
2020-10-16 19:42:12 +02:00
2021-03-10 12:58:38 +01:00
# Header
2022-02-25 13:57:13 +01:00
#+begin_src c :comments org :tangle (eval h_func)
2021-03-10 12:58:38 +01:00
void qmckl_lock (qmckl_context context);
void qmckl_unlock(qmckl_context context);
#+end_src
# Source
2022-02-24 19:06:19 +01:00
#+begin_src c :tangle (eval c) :exports none
2021-03-30 22:40:56 +02:00
void qmckl_lock(qmckl_context context) {
2021-03-10 12:58:38 +01:00
if (context == QMCKL_NULL_CONTEXT)
return ;
2022-04-04 12:11:26 +02:00
qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
2021-03-18 18:02:06 +01:00
errno = 0;
2021-03-10 12:58:38 +01:00
int rc = pthread_mutex_lock( &(ctx->mutex) );
2021-03-18 18:02:06 +01:00
if (rc != 0) {
2021-03-30 14:51:23 +02:00
fprintf(stderr, "DEBUG qmckl_lock:%s\n", strerror(rc) );
2021-03-18 18:02:06 +01:00
fflush(stderr);
}
2021-03-10 12:58:38 +01:00
assert (rc == 0);
2021-03-30 14:51:23 +02:00
ctx->lock_count += 1;
2021-03-10 12:58:38 +01:00
}
2021-03-30 14:51:23 +02:00
void qmckl_unlock(const qmckl_context context) {
2022-04-04 12:11:26 +02:00
qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
2021-03-10 12:58:38 +01:00
int rc = pthread_mutex_unlock( &(ctx->mutex) );
2021-03-18 18:02:06 +01:00
if (rc != 0) {
2021-03-30 14:51:23 +02:00
fprintf(stderr, "DEBUG qmckl_unlock:%s\n", strerror(rc) );
2021-03-18 18:02:06 +01:00
fflush(stderr);
}
2021-03-10 12:58:38 +01:00
assert (rc == 0);
2021-03-30 14:51:23 +02:00
ctx->lock_count -= 1;
2021-03-10 12:58:38 +01:00
}
#+end_src
2021-03-30 14:51:23 +02:00
** TODO Copy
2021-03-10 12:58:38 +01:00
2021-03-30 22:40:56 +02:00
~qmckl_context_copy~ makes a deep copy of a context. It returns
2021-03-10 12:58:38 +01:00
~QMCKL_NULL_CONTEXT~ upon failure.
# Header
2021-03-30 14:51:23 +02:00
#+begin_src c :comments org :tangle (eval h_func) :exports none
2022-02-24 19:06:19 +01:00
/*
qmckl_context qmckl_context_copy(const qmckl_context context);
2022-02-24 19:06:19 +01:00
*/
2021-03-10 12:58:38 +01:00
#+end_src
2020-10-14 00:52:50 +02:00
2021-04-30 01:26:19 +02:00
2021-03-10 12:58:38 +01:00
# Source
2022-02-24 19:06:19 +01:00
#+begin_src c :tangle (eval c) :exports none
qmckl_context qmckl_context_copy(const qmckl_context context) {
2020-10-14 00:52:50 +02:00
2020-11-05 00:46:19 +01:00
const qmckl_context checked_context = qmckl_context_check(context);
2021-03-10 12:58:38 +01:00
if (checked_context == QMCKL_NULL_CONTEXT) {
return QMCKL_NULL_CONTEXT;
2020-10-16 19:42:12 +02:00
}
2021-03-30 22:40:56 +02:00
/*
qmckl_lock(context);
{
2021-04-30 01:26:19 +02:00
2021-03-30 22:40:56 +02:00
const qmckl_context_struct* const old_ctx =
2022-04-04 12:11:26 +02:00
(qmckl_context_struct*) checked_context;
2021-04-30 01:26:19 +02:00
2021-03-30 22:40:56 +02:00
qmckl_context_struct* const new_ctx =
2022-04-04 12:11:26 +02:00
(qmckl_context_struct*) malloc (context, sizeof(qmckl_context_struct));
2021-04-30 01:26:19 +02:00
2021-03-30 22:40:56 +02:00
if (new_ctx == NULL) {
qmckl_unlock(context);
return QMCKL_NULL_CONTEXT;
}
2021-04-30 01:26:19 +02:00
* Copy the old context on the new one *
* TODO Deep copies should be done here *
2021-03-30 22:40:56 +02:00
memcpy(new_ctx, old_ctx, sizeof(qmckl_context_struct));
2021-04-30 01:26:19 +02:00
2021-03-30 22:40:56 +02:00
qmckl_unlock( (qmckl_context) new_ctx );
2021-04-30 01:26:19 +02:00
2021-03-30 22:40:56 +02:00
return (qmckl_context) new_ctx;
2020-10-14 00:52:50 +02:00
}
2021-03-30 22:40:56 +02:00
qmckl_unlock(context);
*/
return QMCKL_NULL_CONTEXT;
2020-10-14 00:52:50 +02:00
}
2021-03-10 12:58:38 +01:00
#+end_src
2020-10-14 01:43:13 +02:00
2021-03-10 12:58:38 +01:00
# Fortran interface
2021-03-30 14:51:23 +02:00
#+begin_src f90 :tangle (eval fh_func) :exports none
2022-02-24 19:06:19 +01:00
! interface
! integer (qmckl_context) function qmckl_context_copy(context) bind(C)
! use, intrinsic :: iso_c_binding
! import
! integer (qmckl_context), intent(in), value :: context
! end function qmckl_context_copy
! end interface
2021-03-10 12:58:38 +01:00
#+end_src
2020-11-05 00:46:19 +01:00
2021-03-10 12:58:38 +01:00
# Test
#+begin_src c :comments link :tangle (eval c_test) :exports none
2021-03-30 22:40:56 +02:00
/*
2021-03-09 01:16:23 +01:00
qmckl_context new_context = qmckl_context_copy(context);
2021-03-10 12:58:38 +01:00
munit_assert_int64(new_context, !=, QMCKL_NULL_CONTEXT);
2020-11-05 15:27:25 +01:00
munit_assert_int64(new_context, !=, context);
munit_assert_int64(qmckl_context_check(new_context), ==, new_context);
2021-03-30 22:40:56 +02:00
*/
2021-03-10 12:58:38 +01:00
#+end_src
** Destroy
The context is destroyed with ~qmckl_context_destroy~, leaving the ancestors untouched.
It frees the context, and returns the previous context.
# Header
2022-02-25 13:57:13 +01:00
#+begin_src c :comments org :tangle (eval h_func)
2022-02-24 19:06:19 +01:00
qmckl_exit_code
qmckl_context_destroy (const qmckl_context context);
2021-03-10 12:58:38 +01:00
#+end_src
# Source
2022-02-24 19:06:19 +01:00
#+begin_src c :tangle (eval c) :exports none
qmckl_exit_code
qmckl_context_destroy (const qmckl_context context)
{
2021-03-10 12:58:38 +01:00
const qmckl_context checked_context = qmckl_context_check(context);
2021-03-30 14:51:23 +02:00
if (checked_context == QMCKL_NULL_CONTEXT) return QMCKL_INVALID_CONTEXT;
2021-03-10 12:58:38 +01:00
2022-04-04 12:11:26 +02:00
qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
2021-03-30 14:51:23 +02:00
assert (ctx != NULL); /* Shouldn't be possible because the context is valid */
2021-03-10 12:58:38 +01:00
2021-03-30 22:40:56 +02:00
qmckl_lock(context);
{
/* Memory: Remove all allocated data */
for (size_t pos = (size_t) 0 ; pos < ctx->memory.array_size ; ++pos) {
if (ctx->memory.element[pos].pointer != NULL) {
free(ctx->memory.element[pos].pointer);
memset( &(ctx->memory.element[pos]), 0, sizeof(qmckl_memory_info_struct) );
ctx->memory.n_allocated -= 1;
}
}
assert (ctx->memory.n_allocated == (size_t) 0);
free(ctx->memory.element);
ctx->memory.element = NULL;
ctx->memory.array_size = (size_t) 0;
}
2021-03-30 14:51:23 +02:00
qmckl_unlock(context);
2021-03-18 19:12:39 +01:00
2021-03-30 22:40:56 +02:00
ctx->tag = INVALID_TAG;
2021-03-18 19:12:39 +01:00
const int rc_destroy = pthread_mutex_destroy( &(ctx->mutex) );
if (rc_destroy != 0) {
2021-03-30 22:40:56 +02:00
/* DEBUG */
2021-03-18 19:12:39 +01:00
fprintf(stderr, "qmckl_context_destroy: %s (count = %d)\n", strerror(rc_destroy), ctx->lock_count);
abort();
}
2021-03-30 22:40:56 +02:00
free(ctx);
2021-03-18 18:02:06 +01:00
2021-03-30 14:51:23 +02:00
return QMCKL_SUCCESS;
2021-03-10 12:58:38 +01:00
}
2021-03-09 01:16:23 +01:00
#+end_src
2021-03-10 12:58:38 +01:00
# Fortran interface
2021-03-30 14:51:23 +02:00
#+begin_src f90 :tangle (eval fh_func) :exports none
2021-03-10 12:58:38 +01:00
interface
2021-03-30 14:51:23 +02:00
integer (qmckl_exit_code) function qmckl_context_destroy(context) bind(C)
2021-03-10 12:58:38 +01:00
use, intrinsic :: iso_c_binding
2021-03-30 14:51:23 +02:00
import
integer (qmckl_context), intent(in), value :: context
2021-03-10 12:58:38 +01:00
end function qmckl_context_destroy
end interface
#+end_src
2020-10-22 00:50:07 +02:00
2021-03-10 12:58:38 +01:00
# Test
#+begin_src c :tangle (eval c_test) :exports none
2021-03-30 22:40:56 +02:00
/* Destroy valid context */
2021-05-11 16:41:03 +02:00
assert(qmckl_context_check(context) == context);
assert(qmckl_context_destroy(context) == QMCKL_SUCCESS);
2021-03-30 22:40:56 +02:00
/* Check that context is destroyed */
#ifndef DEBUG
2021-05-11 16:41:03 +02:00
assert(qmckl_context_check(context) != context);
assert(qmckl_context_check(context) == QMCKL_NULL_CONTEXT);
2021-03-30 22:40:56 +02:00
/* Destroy invalid context */
2021-05-11 16:41:03 +02:00
assert(qmckl_context_destroy(QMCKL_NULL_CONTEXT) == QMCKL_INVALID_CONTEXT);
#endif
2021-03-09 01:16:23 +01:00
#+end_src
2021-03-05 03:45:30 +01:00
2021-03-09 01:16:23 +01:00
* End of files :noexport:
2021-03-05 03:45:30 +01:00
2020-10-16 13:58:05 +02:00
2021-03-30 14:51:23 +02:00
#+begin_src c :comments link :tangle (eval h_private_type)
2021-03-09 01:16:23 +01:00
#endif
#+end_src
2021-03-10 12:58:38 +01:00
2021-03-09 01:16:23 +01:00
*** Test
#+begin_src c :comments link :tangle (eval c_test)
2021-05-11 16:41:03 +02:00
return 0;
2020-10-22 00:50:07 +02:00
}
2021-03-09 01:16:23 +01:00
#+end_src
2020-10-16 13:58:05 +02:00
2021-04-30 01:26:19 +02:00