/*	WebDownloader for X-Window
 *	Copyright (C) 1999-2002 Koshelev Maxim
 *	This Program is free but not GPL!!! You can't modify it
 *	without agreement with author. You can't distribute modified
 *	program but you can distribute unmodified program.
 *
 *	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.
 */

#include <pthread.h>
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include "dlist.h"
#include "face/log.h"
#include "var.h"
#include "ntlocale.h"
#include "signal.h"

static pthread_key_t THREADS_KEY;
static pthread_once_t THREADS_KEY_ONCE=PTHREAD_ONCE_INIT;

static void my_pthread_key_destroy(void *key) {
	char *temp=(char *)key;
	if (temp) delete[] temp;
};

static void my_pthread_key_alloc() {
	pthread_key_create(&THREADS_KEY,my_pthread_key_destroy);
};

void my_pthread_key_init() {
	tDownload *temp;
	pthread_once(&THREADS_KEY_ONCE,my_pthread_key_alloc);
	pthread_setspecific(THREADS_KEY,new char[sizeof(temp)]);
};

tDownload **my_pthread_key_get() {
	return (tDownload **)pthread_getspecific(THREADS_KEY);
};


void my_pthread_key_set(tDownload *what){
	tDownload **temp=my_pthread_key_get();
	if (temp) *temp=what;
};

void signal_handler(int num) {
	tDownload **temp=(my_pthread_key_get());
	if (temp){
		(*temp)->LOG->add(_("Download  was stopped by user"),LOG_WARNING);
		if ((*temp)->segments)
			(*temp)->segments->save();
		D4X_UPDATE.add(*temp,DOWNLOAD_REAL_STOP);
	};
	pthread_exit(NULL);
};

void init_signal_handler() {
	struct sigaction action,old_action;
	action.sa_handler=signal_handler;
	action.sa_flags=0;
	sigaction(SIGUSR1,&action,&old_action);
	sigset_t oldmask,newmask;
	sigemptyset(&newmask);
	sigaddset(&newmask,SIGINT);
	sigaddset(&newmask,SIGTERM);
	sigaddset(&newmask,SIGUSR2);
	sigaddset(&newmask,SIGUSR1);
	pthread_sigmask(SIG_BLOCK,&newmask,&oldmask);
};


int stop_thread(tDownload *what) {
	if (what->thread_id==0)  return 1;
	what->STOPPED_BY_USER=true;
	return(pthread_kill(what->thread_id,SIGUSR1));
};

void real_stop_thread(tDownload *what) {
	int *rc;
	if (what->thread_id)
		pthread_join(what->thread_id,(void **)&rc);
	what->delete_who();
	what->thread_id=0;
};


void my_pthreads_mutex_init(pthread_mutex_t *lock){
#if defined(__linux__)
/* manual page for mutexes said that mutexes in linux is fast by
   default...
 */
//	pthread_mutexattr_setkind_np(&ma,PTHREAD_MUTEX_FAST_NP);
	pthread_mutex_init(lock,NULL);
#else
	pthread_mutexattr_t ma;
	pthread_mutexattr_init(&ma);
#if !defined (__sparc__) && !defined(__mips__)
	pthread_mutexattr_settype(&ma,PTHREAD_MUTEX_NORMAL);
#elif defined(__mips__)
	pthread_mutexattr_settype(&ma,MUTEX_TYPE_NORMAL);	
#endif
	pthread_mutex_init(lock,&ma);
	pthread_mutexattr_destroy(&ma);
#endif
};


using namespace d4x;

USR1Off2On::USR1Off2On(){
	tDownload **temp=(my_pthread_key_get());
	if (temp && (*temp)->STOPPED_BY_USER)
		signal_handler(SIGUSR1);
	
	sigset_t oldmask,newmask;
	sigemptyset(&newmask);
	sigaddset(&newmask,SIGUSR1);
	pthread_sigmask(SIG_UNBLOCK,&newmask,&oldmask);
};

USR1Off2On::~USR1Off2On(){
	sigset_t oldmask,newmask;
	sigemptyset(&newmask);
	sigaddset(&newmask,SIGUSR1);
	pthread_sigmask(SIG_BLOCK,&newmask,&oldmask);
};


USR1On2Off::USR1On2Off(){
	sigset_t oldmask,newmask;
	sigemptyset(&newmask);
	sigaddset(&newmask,SIGUSR1);
	pthread_sigmask(SIG_UNBLOCK,&newmask,&oldmask);
};

USR1On2Off::~USR1On2Off(){
	tDownload **temp=(my_pthread_key_get());
	if (temp && (*temp)->STOPPED_BY_USER)
		signal_handler(SIGUSR1);
	
	sigset_t oldmask,newmask;
	sigemptyset(&newmask);
	sigaddset(&newmask,SIGUSR1);
	pthread_sigmask(SIG_UNBLOCK,&newmask,&oldmask);
};


syntax highlighted by Code2HTML, v. 0.9.1