<commit_before>/*
 * Copyright (C) 2010-2016 <NAME> <<EMAIL>>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU 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.
 */

#include "pmem.h"
#include "pmutex.h"
#include "puthread.h"

#include <stdlib.h>
#include <time.h>
#include <string.h>

#include <windows.h>

typedef HANDLE puthread_hdl;

struct _PUThread {
	puthread_hdl		hdl;
	pboolean		joinable;
	PUThreadPriority	prio;
};

struct _PUThreadKey {
	DWORD			key_idx;
	PDestroyFunc		free_func;
};

typedef struct __PUThreadDestructor _PUThreadDestructor;

struct __PUThreadDestructor {
	DWORD			key_idx;
	PDestroyFunc		free_func;
	_PUThreadDestructor	*next;
};

static _PUThreadDestructor * volatile __tls_destructors;
static PMutex *__tls_mutex = NULL;

static int p_uthread_priority_map[P_UTHREAD_PRIORITY_HIGHEST + 1];

void
__p_uthread_init (void)
{
	if (__tls_mutex == NULL)
		__tls_mutex = p_mutex_new ();

	p_uthread_priority_map[P_UTHREAD_PRIORITY_LOWEST]	= THREAD_PRIORITY_LOWEST;
	p_uthread_priority_map[P_UTHREAD_PRIORITY_LOW]		= THREAD_PRIORITY_BELOW_NORMAL;
	p_uthread_priority_map[P_UTHREAD_PRIORITY_NORMAL]	= THREAD_PRIORITY_NORMAL;
	p_uthread_priority_map[P_UTHREAD_PRIORITY_HIGH]		= THREAD_PRIORITY_ABOVE_NORMAL;
	p_uthread_priority_map[P_UTHREAD_PRIORITY_HIGHEST]	= THREAD_PRIORITY_HIGHEST;
}

void
__p_uthread_shutdown (void)
{
	_PUThreadDestructor *destr;

	if (__tls_mutex != NULL) {
		p_mutex_free (__tls_mutex);
		__tls_mutex = NULL;
	}

	__p_uthread_win32_thread_detach ();

	destr = __tls_destructors;

	while (destr != NULL) {
		_PUThreadDestructor *next_destr = destr->next;

		TlsFree (destr->key_idx);
		p_free (destr);

		destr = next_destr;
	}
}

void
__p_uthread_win32_thread_detach (void)
{
	pboolean was_called;

	do {
		_PUThreadDestructor *destr;

		was_called = FALSE;

		for (destr = __tls_destructors; destr; destr = destr->next) {
			ppointer value;

			value = TlsGetValue (destr->key_idx);

			if (value != NULL && destr->free_func != NULL) {
				TlsSetValue (destr->key_idx, NULL);
				destr->free_func (value);
				was_called = TRUE;
			}
		}
	} while (was_called);
}

static DWORD
__p_uthread_get_tls_key (PUThreadKey *key)
{
	DWORD tls_key = key->key_idx;

	if (tls_key != TLS_OUT_OF_INDEXES)
		return tls_key;

	p_mutex_lock (__tls_mutex);

	tls_key = key->key_idx;

	if (tls_key == TLS_OUT_OF_INDEXES) {<commit_msg>Fix thread calls order on Windows<commit_after>/*
 * Copyright (C) 2010-2016 <NAME> <<EMAIL>>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU 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.
 */

#include "pmem.h"
#include "pmutex.h"
#include "puthread.h"

#include <stdlib.h>
#include <time.h>
#include <string.h>

#include <windows.h>

typedef HANDLE puthread_hdl;

struct _PUThread {
	puthread_hdl		hdl;
	pboolean		joinable;
	PUThreadPriority	prio;
};

struct _PUThreadKey {
	DWORD			key_idx;
	PDestroyFunc		free_func;
};

typedef struct __PUThreadDestructor _PUThreadDestructor;

struct __PUThreadDestructor {
	DWORD			key_idx;
	PDestroyFunc		free_func;
	_PUThreadDestructor	*next;
};

static _PUThreadDestructor * volatile __tls_destructors;
static PMutex *__tls_mutex = NULL;

static int p_uthread_priority_map[P_UTHREAD_PRIORITY_HIGHEST + 1];

void
__p_uthread_win32_thread_detach (void)
{
	pboolean was_called;

	do {
		_PUThreadDestructor *destr;

		was_called = FALSE;

		for (destr = __tls_destructors; destr; destr = destr->next) {
			ppointer value;

			value = TlsGetValue (destr->key_idx);

			if (value != NULL && destr->free_func != NULL) {
				TlsSetValue (destr->key_idx, NULL);
				destr->free_func (value);
				was_called = TRUE;
			}
		}
	} while (was_called);
}

void
__p_uthread_init (void)
{
	if (__tls_mutex == NULL)
		__tls_mutex = p_mutex_new ();

	p_uthread_priority_map[P_UTHREAD_PRIORITY_LOWEST]	= THREAD_PRIORITY_LOWEST;
	p_uthread_priority_map[P_UTHREAD_PRIORITY_LOW]		= THREAD_PRIORITY_BELOW_NORMAL;
	p_uthread_priority_map[P_UTHREAD_PRIORITY_NORMAL]	= THREAD_PRIORITY_NORMAL;
	p_uthread_priority_map[P_UTHREAD_PRIORITY_HIGH]		= THREAD_PRIORITY_ABOVE_NORMAL;
	p_uthread_priority_map[P_UTHREAD_PRIORITY_HIGHEST]	= THREAD_PRIORITY_HIGHEST;
}

void
__p_uthread_shutdown (void)
{
	_PUThreadDestructor *destr;

	if (__tls_mutex != NULL) {
		p_mutex_free (__tls_mutex);
		__tls_mutex = NULL;
	}

	__p_uthread_win32_thread_detach ();

	destr = __tls_destructors;

	while (destr != NULL) {
		_PUThreadDestructor *next_destr = destr->next;

		TlsFree (destr->key_idx);
		p_free (destr);

		destr = next_destr;
	}
}

static DWORD
__p_uthread_get_tls_key (PUThreadKey *key)
{
	DWORD tls_key = key->key_idx;

	if (tls_key != TLS_OUT_OF_INDEXES)
		return tls_key;

	p_mutex_lock (__tls_mutex);

	tls_key = key->key_idx;

	if (tls_key == TLS_OUT_OF_INDEXES) {
{'fraction_non_alphanumeric': 0.08853992649515537, 'fraction_numerical': 0.00835282325425994, 'mean_word_length': 4.904339250493097, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2926770', 'n_tokens_mistral': 2420, 'n_tokens_neox': 2257, 'n_words': 553}