/*
*******************************************************************************
\file mt.h
\brief Multithreading
\project bee2 [cryptographic library]
\created 2014.10.10
\version 2023.02.02
\copyright The Bee2 authors
\license Licensed under the Apache License, Version 2.0 (see LICENSE.txt).
*******************************************************************************
*/

/*!
*******************************************************************************
\file mt.h
\brief Поддержка многозадачности

\pre Все входные указатели действительны, если не оговорено противное.
*******************************************************************************
*/

#ifndef __BEE2_MT_H
#define __BEE2_MT_H

#include "bee2/defs.h"

#ifdef __cplusplus
extern "C" {
#endif

/*!
*******************************************************************************
\file mt.h

\section mt-mtx Мьютексы

Мьютексы — это объект, который может находиться в одном из двух состояний —
"заблокирован" или "разблокирован". Поток блокирует мьютекс с помощью функций
mtMtxLock(), mtMtxTryLock() и снимает блокировку с помощью функции
mtMtxUnlock(). Заблокировать можно только разблокированный мьютекс. Поэтому
вызов mtMtxLock() повлечет приостановку выполнения потока вплоть до
разблокировки мьютекса.

С помощью мьютексов можно синхронизировать доступ к общим объектам потоков.
Перед досупом к объекту каждый из потоков должен заблокировать мьютекс,
а после операции над объектом разблокировать его.

Управление мьютексами реализуется по схемам, заданным в стандарте
языка Си ISO/IEC 9899:2011 (см. заголовочный файл threads.h).

Интерфейс мьютексов упрощен по сравнению со стандартом:
ошибки при блокировке и разблокировке мьютекса не предполагаются.

Если операционная система не распознана, то мьютексы будут
"положительно пустыми": они всегда будут успешно создаваться, блокироваться
и разблокироваться, хотя за этими действиями не будет стоять никакого
функционала.

\remark В реализации для Windows используются облегченные мьютексы --
так называемые критические секции (critical sections).

\typedef mt_mtx_t
\brief Мьютекс
*******************************************************************************
*/

#ifdef OS_WIN
	#include <windows.h>
	typedef CRITICAL_SECTION mt_mtx_t;
#elif defined OS_UNIX
	#include <pthread.h>
	typedef pthread_mutex_t mt_mtx_t;
#else
	typedef bool_t mt_mtx_t;
#endif

/*!	\brief Создание мьютекса

	Создается мьютекс mtx.
	\return Признак успеха.
	\post В случае успеха мьютекс корректен.
*/
bool_t mtMtxCreate(
	mt_mtx_t* mtx		/*!< [out] мьютекс */
);

/*!	\brief Корректный мьютекс?

	Проверяется корректность мьютекса mtx.
	\return Признак корректности.
*/
bool_t mtMtxIsValid(
	const mt_mtx_t* mtx	/*!< [in] мьютекс */
);

/*!	\brief Блокировка мьютекса

	Мьютекс mtx блокируется.
	\pre Мьютекс корректен.
	\remark Если мьютекс заблокирован в момент вызова, то ожидается	снятие
	блокировки (в другом потоке).
*/
void mtMtxLock(
	mt_mtx_t* mtx		/*!< [in,out] мьютекс */
);

/*!	\brief Разблокировка мьютекса

	Мьютекс mtx разблокируется.
	\pre mtMtxUnlock() < mtMtxLock().
	\pre Мьютекс корректен.
*/
void mtMtxUnlock(
	mt_mtx_t* mtx		/*!< [in,out] мьютекс */
);

/*!	\brief Закрытие мьютекса

	Мьютекс mtx закрывается.
	\pre Мьютекс корректен и не заблокирован.
	\pre mtMtxClose() < mtMtxCreate().
	\remark Закрытие заблокированного мьютекса может привести к непредсказуемым
	последствиям.
*/
void mtMtxClose(
	mt_mtx_t* mtx		/*!< [in,out] мьютекс */
);

/*!
*******************************************************************************
\file mt.h

\section mt-thrd Управление потоками

Управление потоками реализуется по схемам, заданным в стандарте языка Си
ISO/IEC 9899:2011 (см. заголовочный файл threads.h).
*******************************************************************************
*/

/*!	\brief Приостановка потока

	Текущий поток приостанавливается на ms миллисекунд.
	\remark 1 секунда = 10^3 миллисекунд = 10^6 микросекунд = 10^9 наносекунд.
	\remark Если операционная система не распознана или операционная система
	не поддерживает многозадачность, то приостановки не будет.
*/
void mtSleep(
	u32 ms		/*!< [in] число миллисекунд */
);

/*!	\brief Вызов один раз

	Функция fn() вызывается в точности один раз даже в ситуации конкурентных
	запросов на вызов из разных потоков. Для контроля однократности вызова
	используется триггер once, первоначально нулевой.
	\expect Триггер once инициализируется нулем и не меняется за пределами
	функции. 
	\return TRUE, если fn() успешно вызвана в данном или предыдущем обращении
	к mtCallOnce(), и FALSE в противном случае.
*/
bool_t mtCallOnce(
	size_t* once,	/*!< [in,out] триггер */
	void (*fn)()	/*!< [in] функция */
);

/*!
*******************************************************************************
\file mt.h

\section mt-atomic Элементарные атомарные операции

Операции выполняются над счетчиками типа size_t, представленными указателями.
Операции атомарны в том смысле, что счетчик защищен от изменения в других
потоках вплоть до завершения операции.

\warning Если указатель на счетчик не выровнен на границу size_t, то поведение
функций может быть непредсказуемым.
*******************************************************************************
*/

/*!	\brief Атомарный инкремент

	Счетчик ctr атомарно увеличивается на 1.
	\remark Возможно переполнение (сверху, overflow).
	\return Новое значение счетчика.
*/
size_t mtAtomicIncr(
	size_t* ctr		/*!< [in,out] счетчик */
);

/*!	\brief Атомарный декремент

	Счетчик ctr атомарно уменьшается на 1.
	\remark Возможно переполнение (снизу, undeflow).
	\return Новое значение счетчика.
*/
size_t mtAtomicDecr(
	size_t* ctr		/*!< [in,out] счетчик */
);

/*!	\brief Атомарное сравнение с заменой

	Счетчик ctr атомарно сравнивается с cmp и, в случае совпадения,
	устанавливается равным swap.
	\return Первоначальное значение счетчика.
*/
size_t mtAtomicCmpSwap(
	size_t* ctr,	/*!< [in,out] счетчик */
	size_t cmp,		/*!< [in] сравниваемое значение */
	size_t swap		/*!< [in] новое значение */
);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* __BEE2_MT_H */
