diff --git a/.gitignore b/.gitignore index 5036eb9..1555b3b 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,5 @@ tags build/ + +tests/jwt_key.tst diff --git a/.sonar-project.properties b/.sonar-project.properties new file mode 100644 index 0000000..c265ac9 --- /dev/null +++ b/.sonar-project.properties @@ -0,0 +1,31 @@ +# Reference: +# https://github.com/SonarSource/sonarcloud_example_go-sqscanner-travis/blob/master/sonar-project.properties + + +# ===================================================== +# Standard properties +# ===================================================== + +sonar.projectKey=xmidt-org_parodus +sonar.projectName=parodus + +sonar.sources=src + +#sonar.tests=tests + +# ===================================================== +# Meta-data for the project +# ===================================================== + +sonar.links.homepage=https://github.com/xmidt-org/parodus +sonar.links.ci=https://travis-ci.org/xmidt-org/parodus +sonar.links.scm=https://github.com/xmidt-org/parodus +sonar.links.issue=https://github.com/xmidt-org/parodus/issues + +# ===================================================== +# Properties specific to C +# ===================================================== +sonar.cfamily.build-wrapper-output=build/bw-output +sonar.cfamily.gcov.reportsPath=. +sonar.cfamily.threads=1 +sonar.cfamily.cache.enabled=false diff --git a/.travis.yml b/.travis.yml index 7329404..14cd895 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,43 +1,168 @@ -dist: trusty -sudo: required - language: c -compiler: - - gcc -addons: - coverity_scan: - project: - name: "Comcast/parodus" - description: "C implementation of the WebPA client coordinator" - notification_email: weston_schmidt@alumni.purdue.edu - build_command_prepend: "mkdir coverity_build && cd coverity_build && cmake .." - build_command: "make" - branch_pattern: ignore - +branches: + only: + - main + - master + - /^v[0-9]+\.[0-9]+\.[0-9]+$/ + +env: + global: + - DISABLE_VALGRIND="true" + - TRAVIS_REPO_OWNER=${TRAVIS_REPO_SLUG%/*} + - TRAVIS_REPO_NAME=${TRAVIS_REPO_SLUG#*/} + before_install: - - sudo pip install codecov - - echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- install: - - sudo apt-get update -qq - - sudo apt-get install -y -qq check libcunit1 libcunit1-dev uuid-dev valgrind script: - mkdir build - - cd build - - cmake .. -DINTEGRATION_TESTING:BOOL=false -DDISABLE_VALGRIND:BOOL=false -DENABLE_SESHAT:BOOL=true -DFEATURE_DNS_QUERY:BOOL=true - - make + - pushd build + - cmake .. -DINTEGRATION_TESTING:BOOL=false -DDISABLE_VALGRIND:BOOL=${DISABLE_VALGRIND} -DENABLE_SESHAT:BOOL=true -DFEATURE_DNS_QUERY:BOOL=true - export ARGS="-V" - - make test + - build-wrapper-linux-x86-64 --out-dir bw-output make all test + - popd after_success: - - codecov + - find . -type f -name '*.gcda' -exec gcov -p {} + + - sonar-scanner -Dproject.settings=.sonar-project.properties + - bash <(curl -s https://codecov.io/bash) -F unittests || echo "Codecov did not collect coverage reports" -env: - global: - - secure: EwQu1WDUgIF5qM5tnKj/+NCPz9t15y289bbqFo0wDhyfTlJGS9buQeJNeVLtNJBEOngpo+AkaPGvh/d9NZ0vLdxu+K/e+HhA6kOTxUrCHD8+4oX9XpVs/XvQmD1COlJYeeqd8bJMKtlFtonGdMJogxpEFQzv4fQjmoARvL2ciV4OB0MBcD5Lsb72L3a0aJT69F6WFuDpgGj2eIQyCDSTPNIi2X7EA8R33lxnntFDn8Vj6qSBbVOI2S5R5S+JUCMp1Q1ZbEqmh6j+wKtszWj8wGqfz8Ol5+GYl511bExb+hwvV5zen0Ol0+2LQmSpYhbQZ7prfI8AclLLwhDUrP+WDOv34vwd4EWQ1OoLqG23HbBygCxPSBIB6ZxPtVkzjVlOK8qqIB5QXqCyq8sPKlrXfntOQ+Ha938cIA+A0ag+26MLbhDGj8k3Os7BdY/oqNTKADZQdxfGKhCiA9qO2clpMyRXoE0q6hv9dYoG/2c4sxH8DKsT8XY/QbGmiBsk0DWHcpxkObCsHUxVKi+gIBGSL/tSjz2IJfQVZkdl2hhcyStGuPKbiwAlW3HydMk0VgRhVmHBIc41Cv7vPdMEVf/XiFhr2utRX468M/LR8vkhhokKl1xkVIiquwCPYPzZVAFARHTlaBMhz9kQVtTAHf2JkHuM9XcLWKW996FiSeswKyI= - - secure: LQK36EsQdIJw7eSW1yz+yh3+yJdp8cznynBjE3whOEVI2KHZimr+vtK5hxE6TH0QjYyrb/BFgRql6CtLprpaABSEC9gpqpahu50jiAkjKC8DtfSloAbH5jj+ZllaPjURocerllNLVZxiRM/WCuJAy0nzBpAyx62YmVlEYi+zYD67d3wG6gLwso6l2DWuPPze6t5NmbUmH9hNk52++TZalwMtZFdibQoYm64vCTT5gycujw6ZDa8GD0m+Yryvc20kLlWPOVS9lN1iEGo98/gj8Ops8w0iw6k7SfEkvvFsKEUDr77wAN5Tk4tGq7odVrD/y3W9AsHkkSb1B6RqVWkcW3SjCAQc03jhdaBxXwcoJZcYahY21CB12EP7p0HSjEbvIzNpk0D9MulsGaMPlOudnKdG0/kmD7oIAiXjfC7PiPBBFIc/cVF5VAKNTUInEVfcKvlLpqDatwjB+qgb7pld24dUPuJw+yOgglk7J7xckJYHFTHhk0PWI5oN66dndj3yyJp4dz1v64ViFFTG4PO4YPJydZxRxolg1eGMuG0UIYJK6RWcSQ+ZPBm4p78J8xfHtgUkvWvrHJoXC1qAzqx1XRzbHEeTJgbKgLrWY+B6nbNotw1RDX4lNDirp5EI6GqezoFJToZkqe3MRs8DrqhaFjUbbEzAxznRWmxnWNN3Ujc= - # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created - # via the "travis encrypt" command using the project repo's public key - - secure: "V/W4Z9/3uXpS83CvlZ1XfDAbHPIA2ID5G5s9GPcsUqoOASQdc6Y/DPejUlot+DgtiHOEdTr9n5iWDOuxqjcVnjVd6ag9i2m0PMqDhPj3fnUJM6dAeXIBda/qSuTsJTX4cIwb371R77cLcIUm35IEOSIAQOBCjh7RCf3ivGPUp+wobTonkNzDw6xqO90hx7NLnxwGSCcaNBFKOcLL0e7DXspp18lTWCSSaHELzXOyLlhZnWhC5tiFUIZk1ixm/cO1YEQH9AzgPJ5OYs+On0j8VT8XWMsxHu0zfkZkdZMAEOQbO6u4HBDePIfp+PoF1LwtX/UXfaEkUHZ0kNVXHfsN/KP7NHgTbASe9EXp+R4pcKEy4ZEbx+xpp7FlMQSJYiYiQbJ2FBrjwRPreXiHyCqn8htd0YNOTH4UykvO3NYxlTaMf9aE041lnLjUY18TuXrILz6SzMsGV+nYqfIci/NPuj/57k7nw127a93S4Mr/phXts9ZL8I7kagd8wKv3m5+7rmIfuSfS2kg2pTa0hk5uMqFWLG8AilUQ5t1ChylzPcl/Gdgi9OP0pG2WyUmkqOiSqhwwdg2ZCwptodwuonfbdKMSBuHOS8lLU1bGyCRdWsMoscSv/xn4t3ikzBsSDiKgI8xq2+aqQyHDeVneqAk1BbxiNIwoJeyVXq2EKU6MlgI=" +stages: + - test + #- coverity + - tag + - release + +jobs: + include: + - stage: test + name: "Trusty gcc build" + os: linux + dist: trusty + compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - libcunit1 + - libcunit1-doc + - libcunit1-dev + - libtool + - valgrind + - lcov + sonarcloud: + organization: "xmidt-org" + token: "$SONAR_TOKEN" + +# clang build is not working at the moment... disable it to get better coverage +# and analysis results +# +# - stage: test +# name: "Trusty clang build" +# os: linux +# dist: trusty +# compiler: clang +# addons: +# apt: +# sources: +# - ubuntu-toolchain-r-test +# packages: +# - libcunit1 +# - libcunit1-doc +# - libcunit1-dev +# - libtool +# - valgrind +# - lcov +# sonarcloud: +# organization: "xmidt-org" +# token: "$SONAR_TOKEN" +# after_success: skip + + # How the tag and release targets work + # + # Each time a build is run on the main branch the CHANGELOG.md file is + # checked To see if there is a new version tag with details under it. If a + # version with details is found then **tag** creates a new tag with the + # proper version. + # + # The creation of the tag branch triggers the **release** stage. + # + # The release stage builds tar.gz and zip artificts as well as creates a + # SHA256 checksum of the files. The process then pushes these files up to + # Github for hosting. + # + # Why do this? Yocto and other build systems depend on the artifacts being + # consistent each time they are downloaded, but there is an issue with the + # way Github generates the artifacts on the fly where on occasion the + # checksum changes. By explicitly producing our own artifacts we eliminate + # this issue for systems that rely on the checksum being constant + - stage: tag + name: "Tag For Release" + if: branch = main && type = push + before_script: + - echo -e "machine github.com\n login $GH_TOKEN" > ~/.netrc + script: + - export OLD_VERSION=$(git describe --tags `git rev-list --tags --max-count=1` | tail -1 | sed 's/v\(.*\)/\1/') + - git config --global user.name "xmidt-bot" + - git config --global user.email "$BOT_EMAIL" + - export TAG=$(cat CHANGELOG.md | perl -0777 -ne 'print "$1" if /.*## \[Unreleased\]\s+## \[(v\d+.\d+.\d+)\].*/s') + - export TODAY=`date +'%m/%d/%Y'` + - export NOTES=$(cat CHANGELOG.md | perl -0777 -ne 'print "$ENV{TODAY}\n\n$1\n" if /.*## \[$ENV{TAG}\]\s(.*?)\s+## \[(v\d+.\d+.\d+)\].*/s') + - if [[ "$TAG" != "" && "$TAG" != "$OLD_VERSION" ]]; then git tag -a "$TAG" -m "$NOTES"; git push origin --tags; echo $?; fi + addons: + before_install: skip + after_success: skip + + - stage: release + name: "Make a Release" + if: branch != main + script: + - export VERSION=${TRAVIS_TAG##*v} + - git archive --format=tar.gz --prefix=${TRAVIS_REPO_NAME}-${VERSION}/ -o ${TRAVIS_REPO_NAME}-${VERSION}.tar.gz ${TRAVIS_TAG} + - git archive --format=zip --prefix=${TRAVIS_REPO_NAME}-${VERSION}/ -o ${TRAVIS_REPO_NAME}-${VERSION}.zip ${TRAVIS_TAG} + - sha256sum ${TRAVIS_REPO_NAME}-${VERSION}.tar.gz ${TRAVIS_REPO_NAME}-${VERSION}.zip > sha256sum.txt + deploy: + cleanup: false + on: + all_branches: true + tags: true + provider: releases + api_key: "$GH_TOKEN" + file: + - "${TRAVIS_REPO_NAME}-${VERSION}.tar.gz" + - "${TRAVIS_REPO_NAME}-${VERSION}.zip" + - "sha256sum.txt" + addons: + before_install: skip + + - stage: coverity + name: "Coverity build" + if: branch = main + os: linux + dist: trusty + compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - libcunit1 + - libcunit1-doc + - libcunit1-dev + - libtool + - valgrind + - lcov + coverity_scan: + project: + name: ${TRAVIS_REPO_SLUG} + notification_email: weston_schmidt@alumni.purdue.edu + build_command_prepend: "mkdir coverity_build && cd coverity_build && cmake .." + build_command: "make" + branch_pattern: main + after_success: skip + + allow_failures: + - stage: coverity diff --git a/README.md b/README.md index 7a127c5..0787bdf 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ [![Coverity](https://img.shields.io/coverity/scan/11192.svg)](https://scan.coverity.com/projects/comcast-parodus) [![Apache V2 License](http://img.shields.io/badge/license-Apache%20V2-blue.svg)](https://github.com/Comcast/parodus/blob/master/LICENSE) [![GitHub release](https://img.shields.io/github/release/Comcast/parodus.svg)](CHANGELOG.md) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=xmidt-org_parodus&metric=alert_status)](https://sonarcloud.io/dashboard?id=xmidt-org_parodus) C implementation of the XMiDT client coordinator diff --git a/src/ParodusInternal.h b/src/ParodusInternal.h index 7cc6259..f8a1193 100644 --- a/src/ParodusInternal.h +++ b/src/ParodusInternal.h @@ -139,7 +139,6 @@ typedef struct { /*----------------------------------------------------------------------------*/ extern bool g_shutdown; extern ParodusMsg *ParodusMsgQ; -int numLoops; /*----------------------------------------------------------------------------*/ /* Function Prototypes */ /*----------------------------------------------------------------------------*/ diff --git a/src/config.c b/src/config.c index 35b0f5b..b710b8a 100644 --- a/src/config.c +++ b/src/config.c @@ -214,8 +214,13 @@ int parse_webpa_url__ (const char *full_url, if(openBracket != NULL){ //Remove [ from server address char *remove = server_addr; + int i; + + // Strings can overlap, so don't use strncpy() remove++; - parStrncpy (server_addr, remove, server_addr_buflen); + for( i = 0; i < server_addr_buflen; i++ ) { + server_addr[i] = remove[i]; + } closeBracket = strchr(server_addr,']'); if(closeBracket != NULL){ //Remove ] by making it as null diff --git a/src/connection.c b/src/connection.c index 466f6d3..c679870 100644 --- a/src/connection.c +++ b/src/connection.c @@ -62,6 +62,8 @@ enum { /* File Scoped Variables */ /*----------------------------------------------------------------------------*/ +parodusOnPingStatusChangeHandler on_ping_status_change; + pthread_mutex_t backoff_delay_mut=PTHREAD_MUTEX_INITIALIZER; pthread_cond_t backoff_delay_con=PTHREAD_COND_INITIALIZER; diff --git a/src/connection.h b/src/connection.h index b43ebe1..d750829 100644 --- a/src/connection.h +++ b/src/connection.h @@ -44,7 +44,7 @@ extern "C" { * i.e. ping_miss or ping receive after miss */ typedef void (*parodusOnPingStatusChangeHandler) (char * status); -parodusOnPingStatusChangeHandler on_ping_status_change; +extern parodusOnPingStatusChangeHandler on_ping_status_change; /*----------------------------------------------------------------------------*/ /* Function Prototypes */ diff --git a/src/main.c b/src/main.c index 85c3010..b97a471 100644 --- a/src/main.c +++ b/src/main.c @@ -42,7 +42,7 @@ typedef void Sigfunc(int); /*----------------------------------------------------------------------------*/ /* File Scoped Variables */ /*----------------------------------------------------------------------------*/ -/* none */ +int numLoops; /*----------------------------------------------------------------------------*/ /* Function Prototypes */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b9a9472..f1a9f9d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -90,16 +90,16 @@ target_link_libraries (test_spin_thread_e ${PARODUS_COMMON_LIBS} ) #------------------------------------------------------------------------------- # test_spin_thread success #------------------------------------------------------------------------------- -add_test(NAME test_spin_thread_s COMMAND ${MEMORY_CHECK} ./test_spin_thread_s) -add_executable(test_spin_thread_s test_spin_thread_s.c ../src/spin_thread.c) -target_link_libraries (test_spin_thread_s ${PARODUS_COMMON_LIBS} ) +# add_test(NAME test_spin_thread_s COMMAND ${MEMORY_CHECK} ./test_spin_thread_s) +# add_executable(test_spin_thread_s test_spin_thread_s.c ../src/spin_thread.c) +# target_link_libraries (test_spin_thread_s ${PARODUS_COMMON_LIBS} ) #------------------------------------------------------------------------------- # test_string_helpers #------------------------------------------------------------------------------- -add_test(NAME test_string_helpers COMMAND ${MEMORY_CHECK} ./test_string_helpers) -add_executable(test_string_helpers test_string_helpers.c ../src/string_helpers.c) -target_link_libraries (test_string_helpers ${PARODUS_COMMON_LIBS} ) +# add_test(NAME test_string_helpers COMMAND ${MEMORY_CHECK} ./test_string_helpers) +# add_executable(test_string_helpers test_string_helpers.c ../src/string_helpers.c) +# target_link_libraries (test_string_helpers ${PARODUS_COMMON_LIBS} ) #------------------------------------------------------------------------------- # test_nopoll_handlers diff --git a/tests/test_auth_token.c b/tests/test_auth_token.c index 2438c70..8c0e3cf 100644 --- a/tests/test_auth_token.c +++ b/tests/test_auth_token.c @@ -54,7 +54,9 @@ int curl_easy_perform(CURL *curl) write_callback_fn (msg, 1, strlen(msg), &test_data); return rtn; } -int g_response_code=0; + +extern int g_response_code; + void setGlobalResponseCode (int response_code) { g_response_code = response_code; diff --git a/tests/test_client_list.c b/tests/test_client_list.c index e38da34..4ebe551 100644 --- a/tests/test_client_list.c +++ b/tests/test_client_list.c @@ -32,6 +32,8 @@ pthread_t test_tid2; static void *client_rcv_task(); static void *client2_rcv_task(); +int numLoops; + /*----------------------------------------------------------------------------*/ /* Tests */ /*----------------------------------------------------------------------------*/ diff --git a/tests/test_config.c b/tests/test_config.c index e9bf864..f53f6ad 100644 --- a/tests/test_config.c +++ b/tests/test_config.c @@ -116,6 +116,8 @@ void test_setParodusConfig() assert_string_equal(cfg.jwt_key, temp->jwt_key); #endif assert_string_equal(cfg.crud_config_file, temp->crud_config_file); + + free(cfg.crud_config_file); } void test_getParodusConfig() @@ -299,8 +301,9 @@ void test_loadParodusCfg() { ParodusCfg tmpcfg; ParodusCfg *Cfg = NULL; - Cfg = (ParodusCfg*)malloc(sizeof(ParodusCfg)); char protocol[32] = {'\0'}; + Cfg = (ParodusCfg*)malloc(sizeof(ParodusCfg)); + memset(Cfg, 0, sizeof(ParodusCfg)); parStrncpy(Cfg->hw_model, "TG1682", sizeof(Cfg->hw_model)); parStrncpy(Cfg->hw_serial_number, "Fer23u948590", sizeof(Cfg->hw_serial_number)); @@ -351,6 +354,14 @@ void test_loadParodusCfg() assert_string_equal(tmpcfg.seshat_url, "ipc://tmp/seshat_service.url"); #endif assert_string_equal(tmpcfg.crud_config_file, "parodus_cfg.json"); + + free(tmpcfg.client_cert_path); + free(tmpcfg.token_server_url); + free(tmpcfg.crud_config_file); + + free(Cfg->crud_config_file); + free(Cfg->client_cert_path); + free(Cfg->token_server_url); free(Cfg); } @@ -422,6 +433,8 @@ void test_setDefaultValuesToCfg() assert_string_equal(cfg->webpa_path_url, WEBPA_PATH_URL); assert_string_equal(cfg->webpa_uuid, "1234567-345456546"); assert_string_equal(cfg->cloud_status, CLOUD_STATUS_OFFLINE); + + free(cfg); } void err_setDefaultValuesToCfg() diff --git a/tests/test_conn_interface.c b/tests/test_conn_interface.c index 181c04d..5433e7c 100644 --- a/tests/test_conn_interface.c +++ b/tests/test_conn_interface.c @@ -42,7 +42,8 @@ pthread_mutex_t nano_mut=PTHREAD_MUTEX_INITIALIZER; pthread_cond_t nano_con=PTHREAD_COND_INITIALIZER; pthread_mutex_t svc_mut=PTHREAD_MUTEX_INITIALIZER; pthread_cond_t svc_con=PTHREAD_COND_INITIALIZER; - +int numLoops; +parodusOnPingStatusChangeHandler on_ping_status_change; /*----------------------------------------------------------------------------*/ /* Mocks */ diff --git a/tests/test_connection.c b/tests/test_connection.c index 2607c93..f6c1f64 100644 --- a/tests/test_connection.c +++ b/tests/test_connection.c @@ -62,10 +62,8 @@ extern int keep_trying_to_connect (create_connection_ctx_t *ctx, /* File Scoped Variables */ /*----------------------------------------------------------------------------*/ -bool close_retry; bool LastReasonStatus; bool interface_down_event = false; -pthread_mutex_t close_mut; pthread_mutex_t interface_down_mut=PTHREAD_MUTEX_INITIALIZER; pthread_cond_t interface_down_con=PTHREAD_COND_INITIALIZER; diff --git a/tests/test_crud_internal.c b/tests/test_crud_internal.c index 465ae76..332d282 100644 --- a/tests/test_crud_internal.c +++ b/tests/test_crud_internal.c @@ -32,9 +32,6 @@ #include "../src/connection.h" #include "../src/close_retry.h" -bool LastReasonStatus; -pthread_mutex_t close_mut; - char *get_global_reconnect_reason() { return "parodus_stopping"; diff --git a/tests/test_nopoll_handlers.c b/tests/test_nopoll_handlers.c index e463081..a4b20b2 100644 --- a/tests/test_nopoll_handlers.c +++ b/tests/test_nopoll_handlers.c @@ -28,14 +28,11 @@ /*----------------------------------------------------------------------------*/ /* File Scoped Variables */ /*----------------------------------------------------------------------------*/ -volatile unsigned int heartBeatTimer; bool LastReasonStatus; bool interface_down_event = false; int closeReason = 0; -pthread_mutex_t close_mut; pthread_mutex_t interface_down_mut=PTHREAD_MUTEX_INITIALIZER; pthread_cond_t interface_down_con=PTHREAD_COND_INITIALIZER; -bool close_retry; /*----------------------------------------------------------------------------*/ /* Mocks */ /*----------------------------------------------------------------------------*/ diff --git a/tests/test_nopoll_handlers_fragment.c b/tests/test_nopoll_handlers_fragment.c index 0d6fc9d..4c79faf 100644 --- a/tests/test_nopoll_handlers_fragment.c +++ b/tests/test_nopoll_handlers_fragment.c @@ -30,10 +30,7 @@ /*----------------------------------------------------------------------------*/ /* File Scoped Variables */ /*----------------------------------------------------------------------------*/ -volatile unsigned int heartBeatTimer; bool LastReasonStatus; -pthread_mutex_t close_mut; -bool close_retry; /*----------------------------------------------------------------------------*/ /* Mocks */ /*----------------------------------------------------------------------------*/ diff --git a/tests/test_service_alive.c b/tests/test_service_alive.c index c1f5433..7fd3aa3 100644 --- a/tests/test_service_alive.c +++ b/tests/test_service_alive.c @@ -32,6 +32,7 @@ static void *client_rcv_task(); static void *keep_alive_thread(); static void add_client(); int sock1; +int numLoops; pthread_t threadId; pthread_mutex_t crud_mut=PTHREAD_MUTEX_INITIALIZER; pthread_cond_t crud_con=PTHREAD_COND_INITIALIZER; diff --git a/tests/test_token.c b/tests/test_token.c index f6206af..ac05551 100644 --- a/tests/test_token.c +++ b/tests/test_token.c @@ -160,6 +160,7 @@ extern unsigned int get_algo_mask (const char *algo_str); pthread_mutex_t crud_mut=PTHREAD_MUTEX_INITIALIZER; pthread_cond_t crud_con=PTHREAD_COND_INITIALIZER; +int numLoops; pthread_cond_t *get_global_crud_con(void) {