/* $Header$ */

/*
 * LinuxThreads specific stuff.
 */

#include	<sys/types.h>

#include	<assert.h>
#include	<limits.h>	/* PTHREAD_THREADS_MAX */
#include	<pthread.h>
#include	<stdio.h>
#include	<unistd.h>
#include	<signal.h>
#include	<sched.h>

#include	"linuxthreads.h"

#define AT_INT(intval)	*((int32_t*)(intval))

/*
 * Internal LinuxThreads variables.
 * Official interface exposed to GDB.
 */
#if 1
extern volatile	int		__pthread_threads_debug;
extern volatile	char		__pthread_handles;
extern char			__pthread_initial_thread;
/*extern volatile	Elf32_Sym*	__pthread_manager_thread;*/
extern const int		__pthread_sizeof_handle;
extern const int		__pthread_offsetof_descr;
extern const int		__pthread_offsetof_pid;
extern volatile	int		__pthread_handles_num;
#endif /* 0 */

/*
 * Notify others.
 */
int
linuxthreads_notify_others(	const int	signotify)
{
	const pid_t			mypid = getpid();
	//const pthread_t			mytid = pthread_self();
	int				i;
	int				threadcount = 0;
	int				threads[PTHREAD_THREADS_MAX];
	int				pid;

	TRACE_FPRINTF((stderr, "theadcount:%d\n", __pthread_handles_num));
	if (__pthread_handles_num==2) {
		/* no threads beside the initial thread */
		return 0;
	}
	/*assert(maxthreads>=3);
	assert(maxthreads>=__pthread_handles_num+2);*/

	// take the initial thread with us
	pid = AT_INT(&__pthread_initial_thread + __pthread_offsetof_pid);
	if (pid!=mypid && pid!=0)
		threads[threadcount++] = pid;
	// don't know why, but always handles[0]==handles[1]
	for (i=1; i<__pthread_handles_num; ++i) {
		const int descr = AT_INT(&__pthread_handles+i*__pthread_sizeof_handle+__pthread_offsetof_descr);
		assert(descr!=0);
		pid = AT_INT(descr+__pthread_offsetof_pid);
		if (pid!=mypid && pid!=0)
			threads[threadcount++] = pid;
	}
	/* TRACE_FPRINTF((stderr, "Stopping threads...")); */
	//for (i=0; i<threadcount; ++i) {
	//	/* TRACE_FPRINTF((stderr, "%d ", threads[i])); */
	//	fflush(stdout);
	//	kill(threads[i], SIGSTOP);	/* Tell thread to stop */
	//}
	/* TRACE_FPRINTF((stderr, " done!\n")); */
	for (i=0; i<threadcount; ++i) {
		TRACE_FPRINTF((stderr, "--- NOTIFYING %d\n", threads[i]));
		kill(threads[i], signotify);	/* Tell to print stack trace */
		/* TRACE_FPRINTF((stderr, "--- WAITING FOR %d\n", threads[i])); */
		/*pause();		 Wait for confirmation. */
	}
	for (i=0; i<threadcount; ++i)
		sched_yield();
	for (i=0; i<threadcount; ++i) {
		TRACE_FPRINTF((stderr, "--- KILLING %d\n", threads[i]));
		kill(threads[i], SIGKILL);	/* Tell thread die :) */
	}
	return __pthread_handles_num;
}