Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  thread.c   Sprache: C

 

/*****************************************************************************
 * thread.c: Test for thread API
 *****************************************************************************
 * Copyright (C) 2020 Marvin Scholz
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#undef NDEBUG
#include <assert.h>

#include <vlc_common.h>
#include <vlc_threads.h>

static int thread_data_magic = 0x1234;
static int thread_return_magic = 0x4321;

// Join thread and verify return
#define TEST_THREAD_JOIN(th, eret)  \
    do {                            \
        void *r;                    \
        vlc_join(th, &r);           \
        assert(r == eret);          \
    } while (0)

// Cancels thread, joins and verifies return
#define TEST_THREAD_CANCEL_JOIN(th)                 \
    do {                                            \
        vlc_cancel(th);                             \
        TEST_THREAD_JOIN(th, VLC_THREAD_CANCELED);  \
    } while (0)

// Join thread and verify magic return value
#define TEST_THREAD_JOIN_MAGIC(th) \
    TEST_THREAD_JOIN(th, &thread_return_magic)

// Spawn thread
#define TEST_THREAD_CLONE(th, f, data) \
    assert(vlc_clone(th, f, data) == 0)

// Spawn thread with magic data
#define TEST_THREAD_CLONE_MAGIC(th, f) \
    TEST_THREAD_CLONE(th, f, &thread_data_magic)


// Structure for the condition tests
struct cond_data
{
    int state; // Count of threads starting, or -1 when threads may exit
    vlc_mutex_t mutex;
    vlc_cond_t  cond_started;  // Signalled when a thread started
    vlc_cond_t  cond_end;      // Waited on by thread before terminating
};

static void cond_data_init(struct cond_data *data, int count)
{
    assert(count > 0);

    data->state = count;
    vlc_mutex_init(&data->mutex);
    vlc_cond_init(&data->cond_started);
    vlc_cond_init(&data->cond_end);
}


/*
 * Test simple thread creation
 */

static void *thread_func_noop(void *data)
{
    assert(data == &thread_data_magic);
    return &thread_return_magic;
}

static void test__thread_create(void)
{
    vlc_thread_t th;
    TEST_THREAD_CLONE_MAGIC(&th, thread_func_noop);
    TEST_THREAD_JOIN_MAGIC(th);
}


/*
 * Test simple thread cancellation
 */

static void *thread_func_loop(void *data)
{
    assert(data == &thread_data_magic);
    while(1) {
        sleep(10);
    }
    return &thread_return_magic;
}

static void test__thread_cancelation(void)
{
    vlc_thread_t th;
    TEST_THREAD_CLONE_MAGIC(&th, thread_func_loop);
    TEST_THREAD_CANCEL_JOIN(th);
}


/*
 * Test thread cancellation with cleanup
 */

static void thread_func_cleanup(void *data)
{
    int *cleanup_state = data;
    assert(*cleanup_state == 0);
    *cleanup_state = 1;
}

static void *thread_func_loop_cleanup(void *data)
{
    int *cleanup_state = data;
    assert(*cleanup_state == 0);

    vlc_cleanup_push(thread_func_cleanup, data);
    while(1) {
        vlc_testcancel();
    }
    vlc_cleanup_pop();

    return &thread_return_magic;
}

static void test__thread_cancelation_with_cleanup(void)
{
    vlc_thread_t th;
    int th_cleanup_state = 0;

    TEST_THREAD_CLONE(&th, thread_func_loop_cleanup, &th_cleanup_state);
    TEST_THREAD_CANCEL_JOIN(th);
    assert(th_cleanup_state == 1);
}


/*
 * - Test broadcasting a condition, waking several threads
 * - Test waiting on condition
 */

static void *thread_func_cond(void *ptr)
{
    struct cond_data *data = ptr;

    // Decrement state and signal start of thread
    vlc_mutex_lock(&data->mutex);
    data->state -= 1;
    vlc_cond_signal(&data->cond_started);
    vlc_mutex_unlock(&data->mutex);

    // Wait until termination is allowed
    vlc_mutex_lock(&data->mutex);
    while (data->state != -1)
        vlc_cond_wait(&data->cond_end, &data->mutex);
    vlc_mutex_unlock(&data->mutex);

    return &thread_return_magic;
}

static void test__cond_broadcast(void)
{
    struct cond_data data;
    vlc_thread_t threads[20];

    cond_data_init(&data, ARRAY_SIZE(threads));

    // Spawn all threads
    for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
        TEST_THREAD_CLONE(&threads[i], thread_func_cond, &data);
    }

    // Wait for all threads to start
    vlc_mutex_lock(&data.mutex);
    while(data.state > 0) {
        vlc_cond_wait(&data.cond_started, &data.mutex);
    }
    vlc_mutex_unlock(&data.mutex);

    // Broadcast threads-may-end condition to all threads
    vlc_mutex_lock(&data.mutex);
    data.state = -1;
    vlc_cond_broadcast(&data.cond_end);
    vlc_mutex_unlock(&data.mutex);

    // Wait for all threads to exit
    for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
        TEST_THREAD_JOIN_MAGIC(threads[i]);
    }
}

static void test__cond_wait(void)
{
    struct cond_data data;
    cond_data_init(&data, 1);

    vlc_thread_t th;
    TEST_THREAD_CLONE(&th, thread_func_cond, &data);

    // Wait for thread to start
    vlc_mutex_lock(&data.mutex);
    while(data.state != 0) {
        vlc_cond_wait(&data.cond_started, &data.mutex);
    }
    vlc_mutex_unlock(&data.mutex);

    // Signal threads-may-end condition to thread
    vlc_mutex_lock(&data.mutex);
    data.state = -1;
    vlc_cond_signal(&data.cond_end);
    vlc_mutex_unlock(&data.mutex);

    // Wait for thread to exit
    TEST_THREAD_JOIN_MAGIC(th);
}


/*
 * Test waiting on condition and let it timeout
 */

static void *thread_func_cond_timeout(void *ptr)
{
    struct cond_data *data = ptr;

    // Decrement state and signal start of thread
    vlc_mutex_lock(&data->mutex);
    data->state -= 1;
    vlc_cond_signal(&data->cond_started);
    vlc_mutex_unlock(&data->mutex);

    vlc_mutex_lock(&data->mutex);

    // Wait until termination is allowed (which is never signalled)
    vlc_tick_t now = vlc_tick_now();
    vlc_tick_t deadline = now + VLC_TICK_FROM_MS(25);
    int ret = vlc_cond_timedwait(&data->cond_end, &data->mutex, deadline);
    assert(ret == ETIMEDOUT);

    vlc_tick_t elapsed = vlc_tick_now() - now;
    assert(elapsed >= VLC_TICK_FROM_MS(25));

    vlc_mutex_unlock(&data->mutex);

    return &thread_return_magic;
}

static void test__cond_wait_timeout(void)
{
    struct cond_data data;
    cond_data_init(&data, 1);

    vlc_thread_t th;
    TEST_THREAD_CLONE(&th, thread_func_cond_timeout, &data);

    // Wait for thread to start
    vlc_mutex_lock(&data.mutex);
    while(data.state != 0) {
        vlc_cond_wait(&data.cond_started, &data.mutex);
    }
    vlc_mutex_unlock(&data.mutex);

    // Never signal that the thread may end, on purpose
    // as it should timeout.

    // Wait for thread exit
    TEST_THREAD_JOIN_MAGIC(th);
}

/*
 * Test latch synchronisation
 */

static void *thread_latch(void *data)
{
    vlc_latch_t *l = data;

    assert(!vlc_latch_is_ready(l));
    vlc_latch_count_down(l, 1);
    vlc_latch_wait(l);
    assert(vlc_latch_is_ready(l));
    return NULL;
}

static void test__latch(void)
{
    vlc_latch_t l;
    vlc_thread_t th;

    vlc_latch_init(&l, 0);
    assert(vlc_latch_is_ready(&l));
    vlc_latch_wait(&l);
    assert(vlc_latch_is_ready(&l));

    vlc_latch_init(&l, 5);
    assert(!vlc_latch_is_ready(&l));
    vlc_latch_count_down(&l, 3);
    assert(!vlc_latch_is_ready(&l));
    vlc_latch_count_down_and_wait(&l, 2);
    assert(vlc_latch_is_ready(&l));
    vlc_latch_wait(&l);
    assert(vlc_latch_is_ready(&l));

    vlc_latch_init(&l, 2);
    TEST_THREAD_CLONE(&th, thread_latch, &l);
    vlc_latch_count_down_and_wait(&l, 1);
    TEST_THREAD_JOIN(th, NULL);
}

/*
 * Test cancelling vlc_tick_sleep
 */

static void *thread_func_tick_sleep(void *data)
{
    assert(data == &thread_data_magic);
    (vlc_tick_sleep)(VLC_TICK_FROM_SEC(10));
    return &thread_return_magic;
}

static void test__vlc_tick_sleep_cancelation(void)
{
    vlc_thread_t th;
    TEST_THREAD_CLONE_MAGIC(&th, thread_func_tick_sleep);
    TEST_THREAD_CANCEL_JOIN(th);
}


/*
 * Test sleeping for delay with vlc_tick_sleep
 */

static void test__vlc_tick_sleep(void)
{
    vlc_tick_t now = vlc_tick_now();

    (vlc_tick_sleep)(VLC_TICK_FROM_MS(25));

    vlc_tick_t elapsed = vlc_tick_now() - now;
    assert(elapsed >= VLC_TICK_FROM_MS(25));
}


/*
 * Main function executing all tests above
 */

int main(void)
{
    alarm(4);

    test__thread_create();
    test__thread_cancelation();
    test__thread_cancelation_with_cleanup();
    test__cond_wait();
    test__cond_wait_timeout();
    test__cond_broadcast();
    test__latch();
    test__vlc_tick_sleep_cancelation();
    test__vlc_tick_sleep();

    return 0;
}

Messung
CHZG
849510093

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104842
#Domains=499162