Added work on making namespaces threadsafe.

This commit is contained in:
Simon Brooke 2026-03-28 11:56:36 +00:00
parent 154cda8da3
commit 1afb1b9fad
38 changed files with 1074 additions and 517 deletions

View file

@ -0,0 +1,40 @@
/**
* payloads/hashtable.h
*
* an ordinary Lisp hashtable - one whose contents are immutable.
*
* Can sensibly sit in any pso from size class 6 upwards.
*
* (c) 2026 Simon Brooke <simon@journeyman.cc>
* Licensed under GPL version 2.0, or, at your option, any later version.
*/
#ifndef __psse_payloads_hashtable_h
#define __psse_payloads_hashtable_h
#include "memory/pointer.h"
/**
* @brief Tag for an ordinary Lisp hashtable - one whose contents are immutable.
* \see NAMESPACETAG for mutable hashtables.
*/
#define HASHTABLETAG "HTB"
/**
* The payload of a hashtable. The number of buckets is assigned at run-time,
* and is stored in n_buckets. Each bucket is something ASSOC can consume:
* i.e. either an assoc list or a further hashtable.
*/
struct hashtable_payload {
struct cons_pointer hash_fn; /* function for hashing values in this hashtable, or `NIL` to use
the default hashing function */
struct cons_pointer write_acl; /* it seems to me that it is likely that the
* principal difference between a hashtable and a
* namespace is that a hashtable has a write ACL
* of `NIL`, meaning not writeable by anyone */
uint32_t n_buckets; /* number of hash buckets */
uint32_t unused; /* for word alignment and possible later expansion */
struct cons_pointer buckets[]; /* actual hash buckets, which should be `NIL`
* or assoc lists or (possibly) further hashtables. */
};
#endif

66
src/c/payloads/mutex.h Normal file
View file

@ -0,0 +1,66 @@
/**
* payloads/mutex.h
*
* A mutex (mutual exclusion lock) cell. Requires a size class 3 object.
*
* (c) 2026 Simon Brooke <simon@journeyman.cc>
* Licensed under GPL version 2.0, or, at your option, any later version.
*/
#ifndef __psse_payloads_mutex_h
#define __psse_payloads_mutex_h
#include <pthread.h>
#include "memory/pointer.h"
/**
* @brief Tag for mutex cell. mutexes are thread-safe locks, required by
* mutable objects.
* \see FUNCTIONTAG.
*/
#define MUTEXTAG "MTX"
/**
* @brief payload for mutex objects.
*
* NOTE that the size of `pthread_mutex_t` is variable dependent on hardware
* architecture, but the largest known size is 40 bytes (five words).
*/
struct mutex_payload {
pthread_mutex_t mutex;
}
struct pso_pointer make_mutex();
/**
* @brief evaluates these forms within the context of a thread-safe lock.
*
* 1. wait until the specified mutex can be locked;
* 2. evaluate each of the forms sequentially in the context of that locked
* mutex;
* 3. if evaluation of any of the forms results in the throwing of an
* exception, catch the exception, unlock the mutex, and then re-throw the
* exception;
* 4. on successful completion of the evaluation of the forms, unlock the mutex
* and return the value of the last form.
*
* @param lock the lock: a mutex (MTX) object;
* @param forms a list of arbitrary Lisp forms.
* @return struct pso_pointer the result.
*/
struct pso_pointer with_lock( struct pso_pointer lock, struct pso_pointer forms);
/**
* @brief as with_lock, q.v. but attempts to obtain a lock and returns an
* exception on failure
*
* 1. attempt to lock the specified mutex;
* 2. if successful, proceed as `with_lock`;
* 3. otherwise, return a specific exception which can be trapped for.
*
* @param lock the lock: a mutex (MTX) object;
* @param forms a list of arbitrary Lisp forms.
* @return struct pso_pointer the result.
*/
struct pso_pointer attempt_with_lock( struct pso_pointer lock, struct pso_pointer forms);

View file

@ -0,0 +1,42 @@
/**
* payloads/namespace.h
*
* a Lisp namespace - a hashtable whose contents are mutable.
*
* Can sensibly sit in any pso from size class 6 upwards.
*
* (c) 2026 Simon Brooke <simon@journeyman.cc>
* Licensed under GPL version 2.0, or, at your option, any later version.
*/
#ifndef __psse_payloads_namespace_h
#define __psse_payloads_namespace_h
#include "memory/pointer.h"
/**
* @brief Tag for a Lisp namespace - a hashtable whose contents are mutable.
* \see HASHTABLETAG for mutable hashtables.
*/
#define NAMESPACETAG "NSP"
/**
* The payload of a namespace. The number of buckets is assigned at run-time,
* and is stored in n_buckets. Each bucket is something ASSOC can consume:
* i.e. either an assoc list or a further namespace.
*/
struct namespace_payload {
struct cons_pointer hash_fn; /* function for hashing values in this namespace, or
* `NIL` to use the default hashing function */
struct cons_pointer write_acl; /* it seems to me that it is likely that the
* principal difference between a hashtable and a
* namespace is that a hashtable has a write ACL
* of `NIL`, meaning not writeable by anyone */
struct cons_pointer mutex; /* the mutex to lock when modifying this namespace.*/
uint32_t n_buckets; /* number of hash buckets */
uint32_t unused; /* for word alignment and possible later expansion */
struct cons_pointer buckets[]; /* actual hash buckets, which should be `NIL`
* or assoc lists or (possibly) further hashtables. */
};
#endif