Skip to content

Commit

Permalink
implement add and get length
Browse files Browse the repository at this point in the history
  • Loading branch information
goatshriek committed Feb 24, 2024
1 parent 1ed56c6 commit dd8f3ad
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 40 deletions.
59 changes: 53 additions & 6 deletions include/private/target/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@
#include <stumpless/target.h>
#include "private/config/wrapper/thread_safety.h"

#define CHAIN_TARGET_ARRAY_SIZE 4
/**
* The length of the array in the chain target structure. Chains where all
* targets fit into this array will require less dynamic memory and fewer
* dereferences, speeding up their performance.
*/
#define CHAIN_TARGET_ARRAY_LENGTH 4

/**
* Internal representation of a chain target.
Expand All @@ -34,7 +39,7 @@
*/
struct chain_target {
/** A static array of targets this chain contains.*/
struct stumpless_target *targets[CHAIN_TARGET_ARRAY_SIZE];
struct stumpless_target *targets[CHAIN_TARGET_ARRAY_LENGTH];
/**
* A dynamic array of targets this chain contains, if the static array is not
* large enough. This will be NULL if it is not needed.
Expand Down Expand Up @@ -70,10 +75,31 @@ struct chain_target {
*
* @since release v2.2.0
*
* @param target The chain target to destroy.
* @param chain The chain target to destroy.
*/
void
destroy_chain_target( const struct chain_target *chain );

/**
* Acquires the lock for the provided chain target.
*
* **Thread Safety: MT-Safe**
* This function is thread safe.
*
* **Async Signal Safety: AS-Unsafe lock**
* This function is not safe to call from signal handlers due to the use of
* a non-reentrant lock.
*
* **Async Cancel Safety: AC-Unsafe lock**
* This function is not safe to call from threads that may be asynchronously
* cancelled, , due to the use of a lock that could be left locked.
*
* @since release v2.2.0
*
* @param chain The chain target to lock. Must not be NULL.
*/
void
destroy_chain_target( const struct chain_target *target );
lock_chain_target( struct chain_target *chain );

/**
* Creates a new empty chain target.
Expand Down Expand Up @@ -114,7 +140,7 @@ new_chain_target( void );
*
* @since release v2.2.0
*
* @param target The chain target to send the entry to.
* @param chain The chain target to send the entry to.
*
* @param entry The entry to send to all targets in this chain.
*
Expand All @@ -123,7 +149,28 @@ new_chain_target( void );
* of the failing target is returned.
*/
int
sendto_chain( struct chain_target *target,
sendto_chain( struct chain_target *chain,
const struct stumpless_entry *entry );

/**
* Releases the lock for the provided chain target.
*
* **Thread Safety: MT-Safe**
* This function is thread safe.
*
* **Async Signal Safety: AS-Unsafe lock**
* This function is not safe to call from signal handlers due to the use of
* a non-reentrant lock.
*
* **Async Cancel Safety: AC-Unsafe lock**
* This function is not safe to call from threads that may be asynchronously
* cancelled, , due to the use of a lock that could be left locked.
*
* @since release v2.2.0
*
* @param chain The chain target to unlock. Must not be NULL.
*/
void
unlock_chain_target( struct chain_target *chain );

#endif /* __STUMPLESS_PRIVATE_TARGET_CHAIN_H */
45 changes: 41 additions & 4 deletions include/stumpless/target/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#ifndef __STUMPLESS_TARGET_CHAIN_H
#define __STUMPLESS_TARGET_CHAIN_H

#include <stddef.h>
#include <stumpless/config.h>
#include <stumpless/target.h>

Expand All @@ -49,6 +50,21 @@ extern "C" {
/**
* Adds a target to an existing chain target.
*
* **Thread Safety: MT-Safe**
* This function is thread safe.
*
* **Async Signal Safety: AS-Unsafe lock heap**
* This function is not safe to call from signal handlers due to the use of a
* non-reentrant lock as well as the use of memory allocation functions when the
* static target array is not big enough. If the chain has space for the new
* target in its static array, then the heap constraint is not present.
*
* **Async Cancel Safety: AC-Unsafe lock heap**
* This function is not safe to call from threads that may be asynchronously
* cancelled, as the lock may not be released, and the memory allocation
* functions may not be AC-Safe. If the chain has space for the new
* target in its static array, then the heap constraint is not present.
*
* @since release v2.2.0
*
* @param chain The chain target to add the target to.
Expand Down Expand Up @@ -84,11 +100,11 @@ stumpless_add_target_to_chain( struct stumpless_target *chain,
*
* @since release v2.2.0
*
* @param target The chain of targets to close.
* @param chain The chain of targets to close.
*/
STUMPLESS_PUBLIC_FUNCTION
void
stumpless_close_chain_and_contents( struct stumpless_target *target );
stumpless_close_chain_and_contents( struct stumpless_target *chain );

/**
* Closes a chain target.
Expand All @@ -112,11 +128,32 @@ stumpless_close_chain_and_contents( struct stumpless_target *target );
*
* @since release v2.2.0
*
* @param target The chain to close.
* @param chain The chain to close.
*/
STUMPLESS_PUBLIC_FUNCTION
void
stumpless_close_chain_only( struct stumpless_target *target );
stumpless_close_chain_only( struct stumpless_target *chain );

/**
* Gets the number of targets currently in a chain.
*
* **Thread Safety: MT-Safe**
* This function is thread safe.
*
* **Async Signal Safety: AS-Unsafe lock**
* This function is not safe to call from signal handlers due to the use of a
* non-reentrant lock.
*
* **Async Cancel Safety: AC-Unsafe lock**
* This function is not safe to call from threads that may be asynchronously
* cancelled, as the lock may not be released.
*
* @since release v2.2.0
*
* @param chain The chain to get the length of.
*/
size_t
stumpless_get_chain_length( const struct stumpless_target *chain );

/**
* Creates a new target chain.
Expand Down
128 changes: 103 additions & 25 deletions src/target/chain.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,40 +29,105 @@
#include "private/target/chain.h"
#include "private/validate.h"

void
stumpless_close_chain_and_contents( struct stumpless_target *target ) {
if( unlikely( !target ) ) {
raise_argument_empty( L10N_NULL_ARG_ERROR_MESSAGE( "target" ) );
return;

struct stumpless_target *
stumpless_add_target_to_chain( struct stumpless_target *chain,
struct stumpless_target *target ) {
struct chain_target *internal_chain;
size_t overflow_count;
size_t old_size;
size_t new_size;
struct stumpless_target **new_targets;
struct stumpless_target *result = chain;

VALIDATE_ARG_NOT_NULL( chain );
VALIDATE_ARG_NOT_NULL( target );

clear_error();

lock_target( chain );

if( chain->type != STUMPLESS_CHAIN_TARGET ) {
raise_target_incompatible( L10N_INVALID_TARGET_TYPE_ERROR_MESSAGE );
result = NULL;
goto finish;
}

if( unlikely( target->type != STUMPLESS_CHAIN_TARGET ) ) {
internal_chain = chain->id;
lock_chain_target( internal_chain );

if( unlikely( internal_chain->target_count >= CHAIN_TARGET_ARRAY_LENGTH ) ) {
overflow_count = internal_chain->target_count - CHAIN_TARGET_ARRAY_LENGTH;
old_size = overflow_count * sizeof( target );
new_size = old_size + sizeof( target );
new_targets = realloc_mem( internal_chain->overflow_targets, new_size );
if( !new_targets ) {
result = NULL;
goto internal_finish;
}

new_targets[overflow_count] = target;
internal_chain->overflow_targets = new_targets;
} else {
internal_chain->targets[internal_chain->target_count] = target;
}

internal_chain->target_count++;

internal_finish:
unlock_chain_target( internal_chain );
finish:
unlock_target( chain );
return result;
}

void
stumpless_close_chain_and_contents( struct stumpless_target *chain ) {
VALIDATE_ARG_NOT_NULL_VOID_RETURN( chain );

if( unlikely( chain->type != STUMPLESS_CHAIN_TARGET ) ) {
raise_target_incompatible( L10N_INVALID_TARGET_TYPE_ERROR_MESSAGE );
return;
}

destroy_chain_target( target->id );
destroy_target( target );
destroy_chain_target( chain->id );
destroy_target( chain );
clear_error();
}

void
stumpless_close_chain_only( struct stumpless_target *target ) {
if( unlikely( !target ) ) {
raise_argument_empty( L10N_NULL_ARG_ERROR_MESSAGE( "target" ) );
return;
}
stumpless_close_chain_only( struct stumpless_target *chain ) {
VALIDATE_ARG_NOT_NULL_VOID_RETURN( chain );

if( unlikely( target->type != STUMPLESS_CHAIN_TARGET ) ) {
if( unlikely( chain->type != STUMPLESS_CHAIN_TARGET ) ) {
raise_target_incompatible( L10N_INVALID_TARGET_TYPE_ERROR_MESSAGE );
return;
}

destroy_chain_target( target->id );
destroy_target( target );
destroy_chain_target( chain->id );
destroy_target( chain );
clear_error();
}

size_t
stumpless_get_chain_length( const struct stumpless_target *chain ) {
struct chain_target *internal_chain;
size_t result;

VALIDATE_ARG_NOT_NULL_UNSIGNED_RETURN( chain );

if( unlikely( !chain->id ) ) {
raise_invalid_id( );
return -1;
}

internal_chain = chain->id;
lock_chain_target( internal_chain );
result = internal_chain->target_count;
unlock_chain_target( internal_chain );
return result;
}

struct stumpless_target *
stumpless_new_chain( const char *name ) {
struct stumpless_target *target;
Expand Down Expand Up @@ -92,10 +157,15 @@ stumpless_new_chain( const char *name ) {
/* private definitions */

void
destroy_chain_target( const struct chain_target *target ) {
config_destroy_mutex( &target->chain_mutex );
free_mem( target->overflow_targets );
free_mem( target );
destroy_chain_target( const struct chain_target *chain ) {
config_destroy_mutex( &chain->chain_mutex );
free_mem( chain->overflow_targets );
free_mem( chain );
}

void
lock_chain_target( struct chain_target *chain ) {
config_lock_mutex( &chain->chain_mutex );
}

struct chain_target *
Expand All @@ -115,18 +185,20 @@ new_chain_target( void ) {
}

int
sendto_chain( struct chain_target *target,
sendto_chain( struct chain_target *chain,
const struct stumpless_entry *entry ) {
size_t i;
int result;
int final_result = 1;
struct stumpless_target *sub_target;

for( i = 0; i < target->target_count; i++ ) {
if( i < CHAIN_TARGET_ARRAY_SIZE ) {
sub_target = target->targets[i];
lock_chain_target( chain );

for( i = 0; i < chain->target_count; i++ ) {
if( i < CHAIN_TARGET_ARRAY_LENGTH ) {
sub_target = chain->targets[i];
} else {
sub_target = target->overflow_targets[i - CHAIN_TARGET_ARRAY_SIZE];
sub_target = chain->overflow_targets[i - CHAIN_TARGET_ARRAY_LENGTH];
}

result = stumpless_add_entry( sub_target, entry );
Expand All @@ -135,5 +207,11 @@ sendto_chain( struct chain_target *target,
}
}

unlock_chain_target( chain );
return final_result;
}

void
unlock_chain_target( struct chain_target *chain ) {
config_unlock_mutex( &chain->chain_mutex );
}
5 changes: 5 additions & 0 deletions src/windows/stumpless.def
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,8 @@ EXPORTS
stumpless_set_sqlite3_insert_sql @221
stumpless_set_sqlite3_prepare @222
stumpless_sqlite3_prepare @223
stumpless_add_target_to_chain @224
stumpless_close_chain_and_contents @225
stumpless_close_chain_only @226
stumpless_get_chain_length @227
stumpless_new_chain @228
Loading

0 comments on commit dd8f3ad

Please sign in to comment.