123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381 |
- /*
- * Copyright (c) 2018-2023 SignalWire, Inc
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
- #include "libks/ks.h"
- #include "tap.h"
- #define MAX_STUFF 200
- static ks_thread_t *threads[MAX_STUFF];
- static ks_thread_t *thread_p;
- static ks_pool_t *pool;
- static ks_mutex_t *mutex;
- static ks_mutex_t *mutex_non_recursive;
- static ks_rwl_t *rwlock;
- static ks_cond_t *cond;
- static int counter1 = 0;
- static int counter2 = 0;
- static int counter3 = 0;
- static int counter4 = 0;
- static int counter5 = 0;
- static int counter6 = 0;
- static int threadscount = 0;
- static int cpu_count = 0;
- #define LOOP_COUNT 10000
- static void *thread_priority(ks_thread_t *thread, void *data)
- {
- while (!ks_thread_stop_requested(thread)) {
- ks_sleep(100000);
- }
- return NULL;
- }
- static void *thread_test_cond_producer_func(ks_thread_t *thread, void *data)
- {
- for (;;) {
- ks_cond_lock(cond);
- if (counter5 >= LOOP_COUNT) {
- ks_cond_unlock(cond);
- break;
- }
- counter5++;
- if (counter6 == 0) {
- ks_cond_signal(cond);
- }
- counter6++;
- ks_cond_unlock(cond);
- *((int *) data) += 1;
- }
- return NULL;
- }
- static void *thread_test_cond_consumer_func(ks_thread_t *thread, void *data)
- {
- int i;
- for (i = 0; i < LOOP_COUNT; i++) {
- ks_cond_lock(cond);
- while (counter6 == 0) {
- ks_cond_wait(cond);
- }
- counter6--;
- ks_cond_unlock(cond);
- }
- return NULL;
- }
- static void check_cond(void)
- {
- int count[MAX_STUFF] = { 0 };
- ks_thread_t * threads[MAX_STUFF] = { 0 };
- int ttl = 0;
- ok( (ks_pool_open(&pool) == KS_STATUS_SUCCESS) );
- ok( (ks_cond_create(&cond, pool) == KS_STATUS_SUCCESS) );
- ks_log(KS_LOG_DEBUG, "Allocated condition");
- int i;
- for(i = 0; i < cpu_count; i++) {
- ok( (ks_thread_create(&threads[i], thread_test_cond_producer_func, &count[i], pool) == KS_STATUS_SUCCESS) );
- }
- ok( (ks_thread_create(&thread_p, thread_test_cond_consumer_func, NULL, pool) == KS_STATUS_SUCCESS) );
- for(i = 0; i < cpu_count; i++) {
- ks_thread_join(threads[i]);
- ttl += count[i];
- }
- ok( (ttl == LOOP_COUNT) );
- ks_thread_join(thread_p);
- ok( (ks_pool_close(&pool) == KS_STATUS_SUCCESS) );
- }
- static void *thread_test_rwlock_func(ks_thread_t *thread, void *data)
- {
- int loop = 1;
- while (1) {
- ks_rwl_read_lock(rwlock);
- if (counter4 == LOOP_COUNT) {
- loop = 0;
- }
- ks_rwl_read_unlock(rwlock);
- if (!loop) {
- break;
- }
- ks_rwl_write_lock(rwlock);
- if (counter4 != LOOP_COUNT) {
- counter4++;
- }
- ks_rwl_write_unlock(rwlock);
- }
- return NULL;
- }
- static void check_rwl(void)
- {
- ks_status_t status;
- ok( (ks_pool_open(&pool) == KS_STATUS_SUCCESS) );
- ok( (ks_rwl_create(&rwlock, pool) == KS_STATUS_SUCCESS) );
- ks_rwl_read_lock(rwlock);
- status = ks_rwl_try_read_lock(rwlock);
- ok( status == KS_STATUS_SUCCESS );
- if ( status == KS_STATUS_SUCCESS ) {
- ks_rwl_read_unlock(rwlock);
- }
- ks_rwl_read_unlock(rwlock);
- int i;
- for(i = 0; i < cpu_count; i++) {
- ok( (ks_thread_create(&threads[i], thread_test_rwlock_func, NULL, pool) == KS_STATUS_SUCCESS) );
- }
- for(i = 0; i < cpu_count; i++) {
- ks_thread_join(threads[i]);
- }
- ok( (ks_pool_close(&pool) == KS_STATUS_SUCCESS) );
- ok( (counter4 == LOOP_COUNT) );
- }
- static void *thread_test_function_cleanup(ks_thread_t *thread, void *data)
- {
- int d = (int)(intptr_t)data;
- if ( d == 1 ) {
- ks_mutex_lock(mutex);
- counter3++;
- ks_mutex_unlock(mutex);
- }
- return NULL;
- }
- static void *thread_test_function_detatched(ks_thread_t *thread, void *data)
- {
- int i;
- int d = (int)(intptr_t)data;
- for (i = 0; i < LOOP_COUNT; i++) {
- ks_mutex_lock(mutex);
- if (d == 1) {
- counter2++;
- }
- ks_mutex_unlock(mutex);
- }
- ks_mutex_lock(mutex);
- threadscount++;
- ks_mutex_unlock(mutex);
- return NULL;
- }
- static void *thread_test_function_attached(ks_thread_t *thread, void *data)
- {
- int i;
- int d = (int)(intptr_t)data;
- void *mem, *last_mem = NULL;
- for (i = 0; i < LOOP_COUNT; i++) {
- if (last_mem) {
- free(last_mem);
- }
- mem = calloc(1, 1024);
- last_mem = mem;
- }
- if (last_mem)
- free(last_mem);
- for (i = 0; i < LOOP_COUNT; i++) {
- ks_mutex_lock(mutex);
- if (d == 1) {
- counter1++;
- }
- ks_mutex_unlock(mutex);
- }
- return NULL;
- }
- static void create_threads_cleanup(void)
- {
- void *d = (void *)(intptr_t)1;
- int i;
- for(i = 0; i < cpu_count; i++) {
- ok( (ks_thread_create(&threads[i], thread_test_function_cleanup, d, pool) == KS_STATUS_SUCCESS) );
- }
- for(i = 0; i < cpu_count; i++) {
- ks_thread_join(threads[i]);
- }
- for(i = 0; i < cpu_count; i++) {
- ks_thread_destroy(&threads[i]);
- }
- }
- static void create_threads_attached(void)
- {
- void *d = (void *)(intptr_t)1;
- int i;
- for(i = 0; i < cpu_count; i++) {
- ok( (ks_thread_create(&threads[i], thread_test_function_attached, d, pool) == KS_STATUS_SUCCESS) );
- }
- }
- static void create_threads_detatched(void)
- {
- ks_status_t status;
- void *d = (void *)(intptr_t)1;
- int i;
- for(i = 0; i < cpu_count; i++) {
- status = ks_thread_create_ex(&threads[i], thread_test_function_detatched, d, KS_THREAD_FLAG_DETACHED, KS_THREAD_DEFAULT_STACK, KS_PRI_DEFAULT, pool);
- ok( status == KS_STATUS_SUCCESS );
- }
- }
- static void check_thread_priority(void)
- {
- ks_status_t status;
- void *d = (void *)(intptr_t)1;
- status = ks_thread_create_ex(&thread_p, thread_priority, d, 0, KS_THREAD_DEFAULT_STACK, KS_PRI_IMPORTANT, pool);
- ok( status == KS_STATUS_SUCCESS );
- todo("Run docker container with an argument --cap-add=sys_nice to satisfy permission to set the scheduling policy\n");
- ok( ks_thread_priority(thread_p) == KS_PRI_IMPORTANT );
- ks_thread_destroy(&thread_p); // To visualize race issue around creating/destroying threads
- ks_thread_request_stop(thread_p);
- ks_thread_join(thread_p);
- ks_thread_destroy(&thread_p);
- end_todo;
- }
- static void join_threads(void)
- {
- int i;
- for(i = 0; i < cpu_count; i++) {
- ok( (KS_STATUS_SUCCESS == ks_thread_join(threads[i])) );
- }
- }
- static void check_attached(void)
- {
- ok( counter1 == (LOOP_COUNT * cpu_count) );
- }
- static void check_detached(void)
- {
- ok( counter2 == (LOOP_COUNT * cpu_count) );
- }
- static void create_pool(void)
- {
- ok( (ks_pool_open(&pool) == KS_STATUS_SUCCESS) );
- }
- static void check_cleanup(void)
- {
- ok( (counter3 == cpu_count) );
- }
- static void check_pool_close(void)
- {
- ok( (ks_pool_close(&pool) == KS_STATUS_SUCCESS) );
- }
- static void create_mutex(void)
- {
- ok( (ks_mutex_create(&mutex, KS_MUTEX_FLAG_DEFAULT, pool) == KS_STATUS_SUCCESS) );
- }
- static void create_mutex_non_recursive(void)
- {
- ok( (ks_mutex_create(&mutex_non_recursive, KS_MUTEX_FLAG_NON_RECURSIVE, pool) == KS_STATUS_SUCCESS) );
- }
- static void test_recursive_mutex(void)
- {
- ks_status_t status;
- ks_mutex_lock(mutex);
- status = ks_mutex_trylock(mutex);
- if (status == KS_STATUS_SUCCESS) {
- ks_mutex_unlock(mutex);
- }
- ok(status == KS_STATUS_SUCCESS);
- ks_mutex_unlock(mutex);
- }
- static void test_non_recursive_mutex(void)
- {
- ks_status_t status;
- ks_mutex_lock(mutex_non_recursive);
- status = ks_mutex_trylock(mutex_non_recursive);
- if (status == KS_STATUS_SUCCESS) {
- ks_mutex_unlock(mutex_non_recursive);
- }
- ok(status != KS_STATUS_SUCCESS);
- ks_mutex_unlock(mutex_non_recursive);
- }
- int main(int argc, char **argv)
- {
- ks_init();
- cpu_count = ks_env_cpu_count() * 4;
- plan(21 + cpu_count * 6);
- diag("Starting testing for %d tests\n", 21 + cpu_count * 6);
- create_pool();
- create_mutex();
- create_mutex_non_recursive();
- test_recursive_mutex();
- test_non_recursive_mutex();
- check_thread_priority();
- create_threads_attached();
- join_threads();
- check_attached();
- create_threads_detatched();
- while (threadscount != cpu_count) ks_sleep(1000000);
- check_detached();
- create_threads_cleanup();
- check_pool_close();
- check_cleanup();
- check_rwl();
- check_cond();
- ks_shutdown();
- done_testing();
- }
|