#if defined(__MINGW32__) || defined(_MSC_VER)
#include <windows.h>
#endif
#include "ngspice/ngspice.h"
#include "ngspice/dvec.h"
#if defined SHARED_MODULE
#ifndef HAVE_LIBPTHREAD
#if defined(__MINGW32__) || defined(_MSC_VER)
#ifdef SRW
#define mutex_lock(a) AcquireSRWLockExclusive(a)
#define mutex_unlock(a) ReleaseSRWLockExclusive(a)
typedef SRWLOCK mutexType;
#else
#define mutex_lock(a) EnterCriticalSection(a)
#define mutex_unlock(a) LeaveCriticalSection(a)
typedef CRITICAL_SECTION mutexType;
#endif
#define thread_self() GetCurrentThread()
#define threadid_self() GetCurrentThreadId()
typedef HANDLE threadId_t;
#define WIN_THREADS
#define THREADS
#endif
#else
#include <pthread.h>
#define mutex_lock(a) pthread_mutex_lock(a)
#define mutex_unlock(a) pthread_mutex_unlock(a)
#define thread_self() pthread_self()
#define threadid_self() 0
typedef pthread_mutex_t mutexType;
typedef pthread_t threadId_t;
#define THREADS
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static bool cont_condition;
#endif
extern mutexType vecreallocMutex;
#endif
struct dvec *dvec_alloc( char *name,
int type, short flags, int length, void *storage)
{
struct dvec * const rv = TMALLOC(struct dvec, 1);
* As of 2019-03, TMALLOC will not return on failure, so this check is
* redundant, but it may be useful if it is decided to allow the
* allocation functions to return NULL on failure and handle recovery
* by the calling functions */
if (!rv) {
return NULL;
}
ZERO(rv, struct dvec);
* the name string belongs to the dvec when this function returns. */
rv->v_name = name;
rv->v_type = type;
rv->v_flags = flags;
rv->v_length = length;
rv->v_alloc_length = length;
rv->v_numdims = 1;
rv->v_dims[0] = length;
if (length == 0) {
rv->v_realdata = NULL;
rv->v_compdata = NULL;
}
else if (flags & VF_REAL) {
* or allocate if not */
rv->v_realdata = storage
? (double *) storage
: TMALLOC(double, length);
rv->v_compdata = NULL;
}
else if (flags & VF_COMPLEX) {
rv->v_realdata = NULL;
rv->v_compdata = storage
? (ngcomplex_t *) storage
: TMALLOC(ngcomplex_t, length);
}
* the ZERO() call */
rv->v_plot = NULL;
rv->v_scale = NULL;
return rv;
}
* its existing allocation with storage if not
*/
void dvec_realloc(struct dvec *v, int length, void *storage)
{
if (isreal(v)) {
if (storage) {
tfree(v->v_realdata);
v->v_realdata = (double *) storage;
}
else {
v->v_realdata = TREALLOC(double, v->v_realdata, length);
}
}
else {
if (storage) {
tfree(v->v_compdata);
v->v_compdata = (ngcomplex_t *) storage;
}
else {
v->v_compdata = TREALLOC(ngcomplex_t, v->v_compdata, length);
}
}
v->v_length = length;
v->v_alloc_length = length;
}
storage for result vectors.
In shared ngspice this may be locked, e.g. during plotting in the primary
thread, while the simulation is running in the background thread. Locking and unlocking
is done by API functions ngSpice_LockRealloc(), ngSpice_UnlockRealloc(). */
void dvec_extend(struct dvec *v, int length)
{
#if defined SHARED_MODULE
mutex_lock(&vecreallocMutex);
#endif
if (isreal(v)) {
v->v_realdata = TREALLOC(double, v->v_realdata, length);
}
else {
v->v_compdata = TREALLOC(ngcomplex_t, v->v_compdata, length);
}
v->v_alloc_length = length;
#if defined SHARED_MODULE
mutex_unlock(&vecreallocMutex);
#endif
}
void dvec_trunc(struct dvec *v, int length)
{
if (v->v_alloc_length <= length) {
v->v_length = length;
}
}
void dvec_free(struct dvec *v)
{
if (v == (struct dvec *) NULL) {
return;
}
if (v->v_name) {
txfree(v->v_name);
}
if (v->v_realdata) {
txfree(v->v_realdata);
}
else if (v->v_compdata) {
txfree(v->v_compdata);
}
txfree(v);
}