/***************************************************************************/
/*                             Druckersoftware                             */
/*                    Copyright (C) Carl Valentin GmbH                     */
/***************************************************************************/

/*
 * test_neg_sema.h
 *
 *  Created on: 22.04.2022
 *      Author: preitinger
 */

#ifndef TEST_TEST_NEG_SEMA_H_
#define TEST_TEST_NEG_SEMA_H_

#include <linux/semaphore.h>
#include <linux/kthread.h>

#include "../KM_CvKernelAccess.h"

typedef struct STestNegSemaEnv {
    struct semaphore sema;
} TestNegSemaEnv;

static TestNegSemaEnv testNegSemaEnv;

static int test_neg_sema_thread(void *arguments) {
    TestNegSemaEnv* e = &testNegSemaEnv;

    pr_info("thread: vor down 1\n");
    down(&e->sema);
    pr_info("thread: vor down 2\n");
    down(&e->sema);
    pr_info("thread: nach down 2\n");

    return 0;
}

static int test_neg_sema_init(void) __attribute((unused));

static int test_neg_sema_init(void) {
    TestNegSemaEnv* e = &testNegSemaEnv;
    int res;
    struct task_struct* task = NULL;


    sema_init(&e->sema, -3);
    res = down_trylock(&e->sema);
    pr_info("down_try...: %d\n", res);
    ASSERT(res == 1); // darf nicht erfolgreich sein da <= 0
    up(&e->sema);
    res = down_trylock(&e->sema);
    pr_info("down_try...: %d\n", res);
    ASSERT(res == 1); // darf nicht erfolgreich sein da <= 0
    up(&e->sema);
    res = down_trylock(&e->sema);
    pr_info("down_try...: %d\n", res);
    ASSERT(res == 1); // darf nicht erfolgreich sein da <= 0
    up(&e->sema);
    res = down_trylock(&e->sema);
    pr_info("down_try...: %d\n", res);
    ASSERT(res == 1); // darf nicht erfolgreich sein da <= 0
    up(&e->sema);
    res = down_trylock(&e->sema);
    pr_info("down_try...: %d\n", res);
    ASSERT(res == 0); // muss nun erfolgreich sein

    sema_init(&e->sema, -3);
    pr_info("nach 2. init\n");
    up(&e->sema);
    up(&e->sema);
    up(&e->sema);
    up(&e->sema);

    {
        task = kthread_create(test_neg_sema_thread, NULL, "test_neg_sema_thread");
        if (IS_ERR(task)) {
            pr_err("thread with fn test_neg_sema_thread could not be started because of error %ld\n", (long) task);
            return -1;
        }
        pr_info("test_neg_sema_thread created.\n");
        wake_up_process(task);
        pr_info("test_neg_sema_thread waked up.\n");

    }

    ssleep(2);
    pr_info("vor letztem up\n");
    up(&e->sema);

    pr_info("test_neg_sema_init done\n");
    return 0;
}
static void test_neg_sema_exit(void) __attribute((unused));
static void test_neg_sema_exit(void) {

}

#endif /* TEST_TEST_NEG_SEMA_H_ */
