/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/



// This is a simple JVMPI implementation, supposed to be fast enought to run on any production environment when you
// have a BigDeal to discover into production.

// The intent of that is to discover when Thread birth and when Thread die.
// The second intent is to find bottlenecks into production systems

// Author is Clebert Suconic
// E-mail of author now is clebert.suconic@jboss.com
// 11-apr-2003

// $Id: jbossInspector.cc,v 1.5 2006/07/27 16:16:54 csuconic Exp $



#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <jvmpi.h>
#include <string.h>
#ifdef WINDOWS
#include <windows.h>
#include <process.h>
#else
#include <unistd.h>
#include <sys/time.h>
#endif

#include <signal.h>

#include <map>
#include <vector>


#ifdef ZLIB
extern "C" {
	#include <zlib.h>
}
#endif

#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif

// DEFINES FOR CONTROL OF EXECUTION
#define IN_IGNORE_LIST 1
#define IN_START_LIST 2
#define IN_INCLUDE_LIST 3

// DEFINES FOR CONTROL OF CLASS-LOADING
#define CLASS_UNLOADED 0
#define CLASS_LOADED 1
#define CLASS_NEEDS_LOAD 2


// JNI implementation
#include "org_jboss_profiler_threadcheck_StartupProfilerCheck.h"

#ifdef CYGWIN
#define WINDOWS
#endif

void startConsoleCheck(char * pendereco, jlong ppid);


// global jvmpi interface pointer
static JVMPI_Interface *jvmpi_interface;
static JNIEnv * jni_interface;

#define CALL(f) (jvmpi_interface->f)

// codigo extraido da JVM (para fazer um sysTimeMillis da mesma forma
#ifdef WINDOWS
#define FT2INT64(ft) ((jlong)(ft).dwHighDateTime << 32 | (jlong)(ft).dwLowDateTime)

	jlong
	sysTimeMillis(void)
	{
	    static jlong fileTime_1_1_70 = 0;
	    SYSTEMTIME st0;
	    FILETIME   ft0;

	    if (fileTime_1_1_70 == 0) {
		/* Initialize fileTime_1_1_70 -- the Win32 file time of midnight
		 * 1/1/70.
		 */

		memset(&st0, 0, sizeof(st0));
		st0.wYear  = 1970;
		st0.wMonth = 1;
		st0.wDay   = 1;
		SystemTimeToFileTime(&st0, &ft0);
		fileTime_1_1_70 = FT2INT64(ft0);
	    }

	    GetSystemTime(&st0);
	    SystemTimeToFileTime(&st0, &ft0);

	    return (FT2INT64(ft0) - fileTime_1_1_70) / 10000;
	}
#else
	jlong
	sysTimeMillis()
	{
	    struct timeval t;
	    gettimeofday(&t, 0);
	    return ((jlong)t.tv_sec) * 1000 + (jlong)(t.tv_usec/1000);
	}

#endif

#ifdef COUNT_METHODS
static int enterMethods=0;
static int exitMethods=0;
#endif

struct _objInformation {
	jobjectID obj;
	void * objData;
	struct _objInformation * next;
};


// utilizado para controlar o nome dos arquivos abertos por thread
struct _filesInfo{
	char nomeArquivo[1024];
	void * fileHandler; // poder tanto faz ser um gzipFile ou FILE *
};

typedef struct _filesInfo FilesInfo;



/*struct _objLinkedList {
        struct _objInformation * root;
        struct _objInformation * end;
}; */


typedef std::map<jobjectID,void *> ObjInfo;


/* Linked list used to handle classLoading*/
static ObjInfo linkedListClasses;
static ObjInfo linkedListThreads;

JVMPI_RawMonitor list_mutex_t=NULL;
static std::vector< void * > linkedListFiles; // para poder execura flush corretamente (principalmente quando se tratar de gzip)

static jlong startTime;
static jlong execTime;
// -1 means that the load was not called
static int profilerRunning=-1;
// if true, the profiler will be started just after the JVM Load
static int wakeupOnStartup=0;
static int profileMemory=1;
// para garantir sincronia entre as chamadas
JVMPI_RawMonitor profileChangeLock;
void changeProfiller();

static FILE * logfile = NULL;
static jlong pid = 0;
static char parametroSocket[255];
static int usingSockets=0;

// Start List is a list where we will start to gathering information. The use of that list is optional.
static int usingStartList=0;
// ClassInfo about the thread
struct _classInfo {
	// If is in ignoreList, we would stop gathering information for that thread
	int isInIgnoreList;
	// If is in startList, and if we are using a startList, we would start gathering information for that thread
	int isInStartList;
	// Controls if the class is on includeList or not.
	int isInIncludeList;
	// IgnoredList are not loaded into files at the first time. But if a object is loaded, it may be necessary
	int isLoaded;

	char * className;
};

// a list can be class or package names
char ** ignoreList=NULL;
int * strLenOnIgnoreList;
int ignoreListSize;

// a list can be class or package names
char ** startList=NULL;
int * strLenOnStartList;
int startListSize;

// a list can be class or package names
char ** includeList=NULL;
int * strLenOnIncludeList;
int includeListSize;

//for transaction tracer
static int transactionTracer = 0;


void loadIgnoreList(int nparametros, char ** parametros) {
	ignoreListSize=0;
	startListSize=0;
	includeListSize=0;
	for (int i=0;i<nparametros;i++) {
		if (strncmp(parametros[i],"ignore=",7)==0) {
			ignoreListSize++;
		} else if (strncmp(parametros[i],"start=",6)==0) {
			startListSize++;
			usingStartList=1;
		} else if (strncmp(parametros[i],"include=",8)==0) {
			includeListSize++;
		}
	}

	if (ignoreListSize!=0) {
	    ignoreList =(char **) malloc(sizeof(char *)*ignoreListSize);
	    strLenOnIgnoreList = (int *)malloc (sizeof(int) * ignoreListSize);
	}

	if (startListSize!=0) {
	    startList =(char **) malloc(sizeof(char *)*startListSize);
	    strLenOnStartList = (int *)malloc (sizeof(int) * startListSize);
	}

	if (includeListSize!=0) {
	    includeList =(char **) malloc(sizeof(char *)*includeListSize);
	    strLenOnIncludeList = (int *)malloc (sizeof(int) * includeListSize);
	}

	int countIgnore=0, countStart=0, countInclude=0;
	for (int i=0;i<nparametros;i++) {
		if (strncmp(parametros[i],"ignore",6)==0) {
			ignoreList[countIgnore] = (char *) malloc(sizeof (char) * strlen(parametros[i] + 1));
			strcpy (ignoreList[countIgnore],parametros[i]+7); // espaco do ignore=
			strLenOnIgnoreList[countIgnore] = strlen(ignoreList[countIgnore]);
			countIgnore++;
		} else if (strncmp(parametros[i],"start",5)==0) {
			startList[countStart] = (char *) malloc(sizeof (char) * strlen(parametros[i] + 1));
			strcpy (startList[countStart],parametros[i]+6); // espaco do start=
			strLenOnStartList[countStart] = strlen(startList[countStart]);
			countStart++;
		}else if (strncmp(parametros[i],"include",7)==0) {
			includeList[countInclude] = (char *) malloc(sizeof (char) * strlen(parametros[i] + 1));
			strcpy (includeList[countInclude],parametros[i]+8); // length of include=
			strLenOnIncludeList[countInclude] = strlen(includeList[countInclude]);
			countInclude++;
		}
	}

	for (int i=0;i<ignoreListSize;i++) fprintf (logfile,"IgnoreList[%d]=%s\n",i,ignoreList[i]);
	for (int i=0;i<startListSize;i++) fprintf (logfile,"StartList[%d]=%s\n",i,startList[i]);
	for (int i=0;i<includeListSize;i++) fprintf (logfile,"IncludeList[%d]=%s(%d)\n",i,includeList[i],strLenOnIncludeList[i]);
	fflush(logfile);
}


// return type is boolean like (0 or 1)
int isInIgnoreList(char * className) {
	for (int i=0;i<ignoreListSize;i++) {
		if (strcmp(ignoreList[i],"*")==0) {
			return 1;
		}
		if (strncmp(ignoreList[i],className,strLenOnIgnoreList[i])==0) return 1;
	}
	return 0;
}

// return type is boolean like (0 or 1)
int isInStartList(char * className) {
	for (int i=0;i<startListSize;i++) {
		if (strncmp(startList[i],className,strLenOnStartList[i])==0) return 1;
	}
	return 0;
}

int isInIncludeList(char * className) {
	for (int i=0;i<includeListSize;i++) {
		if (strncmp(includeList[i],className,strLenOnIncludeList[i])==0) return 1;

                //for tracer
                else if (transactionTracer)
                {
                   char * s1[] = {"Exception","Error"};
                   char *sp;
                   for (int i=0; i<2; i++)
                   {
                      sp = strstr(className,s1[i]);
                      if (sp!=NULL) {
                         if (strcmp(sp,s1[i])==0) return 1;
                      }
                   }
                }

	}
	return 0;
}


/* Data access Lock */
JVMPI_RawMonitor linked_list_lock;

#ifdef ZLIB


static int gzwritelock=0;

inline gzFile gzopenlocal (char * strFileName,char * mode) {
	gzFile file = gzopen(strFileName,mode);
	//gz_stream * ptr = (gz_stream *) file;
	//ptr->zCont=0;
	return file;
}

inline int gzwritelocal (gzFile file,voidp buf, unsigned len, const char * msg)
{
	if (gzwritelock) {
		//fprintf (logfile,"\n\n\n\n*******************************************************\nRealizando uma chamada a gzwrite quando nao deveria em %s\n\n\n\n",msg);
		fflush(logfile);
		return Z_OK;
	}
	int retValue = gzwrite(file,buf,len);
	if (retValue==0) {
		fflush(logfile);
	}

	return retValue;
}
#endif

// retorna o node incluido
void addObj(ObjInfo& linkedList, jobjectID obj, void * objData) {

	jvmpi_interface->RawMonitorEnter(list_mutex_t);
	
	linkedList.insert( std::make_pair(obj,objData) );

	jvmpi_interface->RawMonitorExit(list_mutex_t);
}

void debugFiles() {
   std::vector<void *>::iterator p;

   fprintf (logfile,"**************** files debug information *********************\n");
   for (p=linkedListFiles.begin();p!=linkedListFiles.end();p++) {
        FilesInfo* fileInfo = (FilesInfo *) *p;
	if (fileInfo->fileHandler!=NULL) {
		fprintf (logfile,"File %s (not closed yet)\n",fileInfo->nomeArquivo);
	} else {
		fprintf (logfile,"File %s (already closed)\n",fileInfo->nomeArquivo);
	}
   }
   fprintf (logfile,"**************** end files debug information report*********************\n");
    fflush(logfile);

}

void addFileOnLinkedList(char * nomeArquivo,void * fileHandler) {
	FilesInfo * filesInfo = (FilesInfo *)malloc(sizeof(FilesInfo));
	strcpy(filesInfo->nomeArquivo,nomeArquivo);
	filesInfo->fileHandler=fileHandler;
	
	jvmpi_interface->RawMonitorEnter(list_mutex_t);
	
	linkedListFiles.insert(linkedListFiles.end(),(void *)filesInfo);

	jvmpi_interface->RawMonitorExit(list_mutex_t);

}


int lookupObj(ObjInfo& linkedList, jobjectID & obj, void ** data) {
   std::map<jobjectID, void *>::iterator p;
   p = linkedList.find(obj);
   if (p != linkedList.end())
   {
      *data = p->second;
      return 1;
   }
   else {
      return 0;
   }
}

int lookupObj(ObjInfo& linkedList, jobjectID & obj) {
	return lookupObj(linkedList,obj,NULL);
}


// Constants for use in registers
//#define CONST_HEADER 255
#define CONST_LOADCLASS 1
#define CONST_LOADMETHOD 2
#define CONST_LOADOBJECT 3
#define CONST_UNLOADOBJECT 4
#define CONST_GCSTART 5
#define CONST_GCFINISH 6
#define CONST_THREADSTART 7
#define CONST_THREADEND 8
#define CONST_ENTERMETHOD 9
#define CONST_EXITMETHOD 10
#define CONST_MONITOR_IN 11
#define CONST_MONITOR_OUT 12

#define CONST_CONTENDED_ENTER 13
#define CONST_CONTENDED_ENTERED 14
#define CONST_CONTENDED_EXIT 15
#define CONST_RAW_CONTENDED_ENTER 16
#define CONST_RAW_CONTENDED_ENTERED 17
#define CONST_RAW_CONTENDED_EXIT 18


static FILE * out = NULL;


static long maxSize=1024*1024*10;

struct _stackInfo {
	int bufferSize;
	int size;
	int * buffer;
};

typedef struct _stackInfo StackInfo;


void debugStack(char * message, StackInfo& stackStatus) {
	fprintf (stderr,"JBossProfiler: %s ",message);
	for (int i=0;i<stackStatus.size;i++) {
		fprintf (stderr,"JBossProfiler: %d ",stackStatus.buffer[i]);
	}
	fprintf (stderr,"\n");
}



void pushStack(StackInfo& handler, int number) {
	// creates a new buffer if necessary
	if (handler.size+1>handler.bufferSize) {
		int newBufferSize=handler.bufferSize+100;
		int * newBuffer =(int *) malloc(sizeof(int)*(newBufferSize));
		if (handler.buffer!=NULL) {
			for (int i=0;i<handler.size;i++) newBuffer[i]=handler.buffer[i];
			handler.bufferSize=newBufferSize;
			free(handler.buffer);
		}
		handler.buffer=newBuffer;
		for (int i=handler.size;i<newBufferSize;i++)newBuffer[i]=0;
	}
	handler.buffer[handler.size++] = number;
}

void initStack(StackInfo& handler) {
	handler.size=0;
	handler.bufferSize=0;
	handler.buffer=NULL;
}

int peekStack(StackInfo& handler) {
	if (handler.size<=0) return 0;
	else
	return handler.buffer[handler.size-1];
}

int popStack(StackInfo& handler) {
	if (handler.size<=0) return 0;

	handler.size--;
	return handler.buffer[handler.size];
}

struct _threadAreaHandler {
#ifdef ZLIB
        gzFile fileHandler;
#else
	FILE * fileHandler;
#endif
        // We just got an startup and because of that, we will gather evedything on this thread (How many startupsEntrys it takes)
        int startupEntry;
        StackInfo stackStatus; // stacks means... 0=regularMetho, 1=ignored,2=startupList
        /* os arquivos abertos tambem ficam em uma lista ligada, para fecha-los
	* em funcao da zlib. Esta classe marca aonde fica este node, para
	* tratar o node.
	*/
	jlong timeCreated;
	jlong clockCreated;
	jint threadNumber;
	// Number of times that some method in ignorelist was called on this thread.
	// This will be used to control I/O on ignored methods
	//jint numberOfIgnoredLevels;
	// number of produced files for the current thread
	char strFileName[1024];
};

typedef struct _threadAreaHandler ThreadHandler;

static int threadsOpened=0;

// 38 bytes Ascii String which identified if the input file is of the expected type
static const char * progID = (const char *) "DPINSP";


// Directory to put log files (passed as parameter on OnLoad)
static char logFileDirectory[1024];

static char mainLogFileName[1024];

// Time_t for producing log files on logFileDirectory
jlong log_start = 0;

/*
  returns an instance of a produced time_t value
*/
void inline getTime() {
	execTime=sysTimeMillis();
	//time(&execTime);
	//return startTime + (time_t)(clock);
}

jlong inline getClock() {
	return CALL(GetCurrentThreadCpuTime)();
}


/*
  Produces a logFileName for Thread output
*/
inline void produceLogFileNameForThread(char * strFileName, jlong timeCalled, jlong clockCalled) {
#ifdef ZLIB
   char * sufix=".log.gz";
#else
   char * sufix=".log";
#endif
#ifdef WINDOWS
	//sprintf(strFileName,"%sserverspy_%ld_thread_%I64d_%I64d_%d%s", logFileDirectory,pid,timeCalled,clockCalled,threadsOpened++,sufix);
	sprintf(strFileName,"%sserverspy_%I64d_thread_%I64d_%I64d_%d%s", logFileDirectory,pid,timeCalled,clockCalled,threadsOpened++,sufix);
#else
	//sprintf(strFileName,"%sserverspy_%ld_thread_%lld_%lld_%d%s", logFileDirectory,pid,timeCalled,clockCalled,threadsOpened++,sufix);
	sprintf(strFileName,"%sserverspy_%lld_thread_%lld_%lld_%d%s", logFileDirectory,pid,timeCalled,clockCalled,threadsOpened++,sufix);
#endif
}

/** Verify Thread area. If null open a new ThreadOutput File*/
#ifdef ZLIB
inline gzFile threadFileOpen(JNIEnv *env_id, jlong timeCalled, jlong clockCalled, ThreadHandler** handler) {
#else
inline FILE * threadFileOpen(JNIEnv *env_id, jlong timeCalled, jlong clockCalled, ThreadHandler** handler) {
#endif
	*handler = (ThreadHandler *)(CALL(GetThreadLocalStorage)(env_id));
	if (*handler==NULL) {
		*handler=(ThreadHandler *)malloc(sizeof(ThreadHandler));
		(*handler)->timeCreated = timeCalled;
		(*handler)->clockCreated = clockCalled;
		(*handler)->threadNumber = threadsOpened;
		(*handler)->fileHandler = NULL;
		(*handler)->startupEntry=0;
		initStack ((*handler)->stackStatus);
		//(*handler)->numberOfIgnoredLevels = 0;

		CALL(SetThreadLocalStorage)(env_id, *handler);
	}

	//if (profilerRunning && (*handler)->fileHandler==NULL) {
	if (profilerRunning>=0 && (*handler)->fileHandler==NULL) {
		produceLogFileNameForThread((*handler)->strFileName,timeCalled,clockCalled);
#ifdef ZLIB
		(*handler)->fileHandler = gzopenlocal ((*handler)->strFileName,"wb");
#else
		(*handler)->fileHandler = fopen ((*handler)->strFileName,"wb");
#endif
		if ((*handler)->fileHandler==NULL) {
			fprintf (logfile,"JBossProfiler Error: Cannot open file %s\n",(*handler)->strFileName);
			fprintf (stderr,"********************************************************");
			fprintf (stderr,"JBossProfiler ERROR: Cannot open file %s\n",(*handler)->strFileName);
			fprintf (stderr,"********************************************************");
			//(*handler)->fileHandler=out;
		}
		addFileOnLinkedList((*handler)->strFileName,(*handler)->fileHandler);
	}


	return (*handler)->fileHandler;
}


/*
  header - Type of register, identified by all defines begining with REGISTER_ at the top of this source file
  time - jlong to be written
  clock - jint to be written
*/
#ifdef ZLIB
inline void writeHeader(jbyte header, jlong* time, jlong* clockCpu, const gzFile outFile) {
#else
inline void writeHeader(jbyte header, jlong* time, jlong* clockCpu, const FILE * outFile) {
#endif
	static jlong lastClock=0;
#ifdef ZLIB
    gzwritelocal (outFile,&header,sizeof(header),"write header1");
	gzwritelocal (outFile,time,sizeof(jlong),"write header2");
	gzwritelocal (outFile,clockCpu,sizeof(jlong),"write header3");
#else
    fwrite (&header,sizeof(header),1,outFile);
	fwrite (time,sizeof(jlong),1,outFile);
	fwrite (clockCpu,sizeof(jlong),1,outFile);
#endif
	//fwrite (&elapsedClock,sizeof(jint),1,outFile);
	//fprintf (logfile,"clockCPU=%I64d\n",*clockCpu);
}

/*
  para uso do GCSTART|GCFINISH|FREE_OBJECT que colocaram seus resultados no main arqchive, sem compressao
  header - Type of register, identified by all defines begining with REGISTER_ at the top of this source file
  time - jlong to be written
  clock - jint to be written
*/
inline void writeHeaderPadrao(const jbyte header, const jlong* time, const jlong* clockCpu, FILE * outFile) {
	static jlong lastClock=0;
    fwrite (&header,sizeof(header),1,outFile);
	fwrite (time,sizeof(jlong),1,outFile);
	fwrite (clockCpu,sizeof(jlong),1,outFile);
	//fwrite (&elapsedClock,sizeof(jint),1,outFile);
	//fprintf (logfile,"clockCPU=%I64d\n",*clockCpu);
}


/*
  Writes...
  PROGID|255 (long)|Time_t|CLOCKS_PER_SEC
  ProgId identified on variable progID
  Write a long with 255 just to check alignment purpose when reading the produced file
*/
inline void writeMainHeader() {
	jint tst = 0xff;
	jlong timeMain = sysTimeMillis();
	//time(&timeMain);

	fwrite (progID,sizeof (char),strlen(progID),out);
	fwrite (&tst,sizeof(tst),1,out);
	fwrite (&timeMain,sizeof(timeMain),1,out);
}

/*
  MESSAGES of LoadClass
  Message LoadClass:
  <constant CONST_LOADCLASS><jlong><jint><classId><sizeOfClassName><str className><numberOfMethods>

  Message LoadMethod:
  <constant CONST_LOADMETHOD><jlong><jint><classId><methodId><sizeOfMethodName><str MethodName><sizeOfSignatureName><strSignatureName>

*/
void inline loadClass(JNIEnv *env_id, jobjectID & class_id,char * className, jint & num_methods, JVMPI_Method * methods ) {
	ThreadHandler * threadHandler;
	jshort i=0;// general purpose local variable
	jshort j=0;// general purpose local variable
	jlong clock = getClock();
    getTime();

	int ignoreResult = isInIgnoreList(className);
	int startResult = isInStartList(className);
	int includeResult = isInIncludeList(className);
	if (startResult) ignoreResult=0;

	struct _classInfo * classInfo = NULL;
	if (!lookupObj(linkedListClasses, class_id, (void **)&classInfo)) {
		classInfo=(struct _classInfo *) malloc(sizeof (struct _classInfo));
		classInfo->isLoaded=0;
		classInfo->isInIgnoreList = ignoreResult;
		classInfo->isInIncludeList = includeResult;
		classInfo->isInStartList = startResult;

		classInfo->className = (char *)malloc(strlen(className)+1);
		strcpy (classInfo->className,className);
		addObj(linkedListClasses,class_id,classInfo);
		if (ignoreResult) {
			return;
		}
	}

	// if the profiler is not running, we are only interested on those classes
	// which are not inside ignoreList
	if (!profilerRunning && !ignoreResult && !startResult && !includeResult && classInfo->isLoaded==2) return;

	if (classInfo->isLoaded==CLASS_LOADED) {
		//fprintf (stderr,"Caution... not supposed to reach classInfo->isLoaded at loadClass\n");
		return;
	} else if (classInfo->isLoaded==CLASS_NEEDS_LOAD) {
		classInfo->isLoaded=CLASS_LOADED;
	}

#ifdef ZLIB
	gzFile threadFile = threadFileOpen(env_id,execTime,clock,&threadHandler);
#else
	FILE * threadFile = threadFileOpen(env_id,execTime,clock,&threadHandler);
#endif

	writeHeader(CONST_LOADCLASS,&execTime,&clock,threadFile);
#ifdef ZLIB
	gzwritelocal (threadFile,&class_id,sizeof(class_id),"loadclass1");
#else
	fwrite (&class_id,sizeof(class_id),1,threadFile);
#endif
	i = strlen(className);
#ifdef ZLIB
	gzwritelocal (threadFile,&i,sizeof(i),"loadclass2");
	gzwritelocal (threadFile,className,sizeof(char)*i,"loadclass3");
	gzwritelocal (threadFile,&num_methods,sizeof(num_methods),"loadclass4");
	for (i=0;i<num_methods;i++) {
	   writeHeader(CONST_LOADMETHOD,&execTime,&clock,threadFile);
	   gzwritelocal (threadFile,&class_id,sizeof(class_id),"loadclass6");
	   gzwritelocal (threadFile,&(methods[i].method_id),sizeof(methods[i].method_id),"loadclass6");
	   j = strlen(methods[i].method_name);
	   gzwritelocal (threadFile,&j,sizeof(j),"loadclass7");
	   gzwritelocal (threadFile,methods[i].method_name,j*sizeof(char),"loadclass8");
	   j = strlen(methods[i].method_signature);
	   gzwritelocal (threadFile,&j,sizeof(j),"loadclass9");
	   gzwritelocal (threadFile,methods[i].method_signature,j*sizeof(char),"loadclass10");
	}
#else
	fwrite (&i,sizeof(i),1,threadFile);
	fwrite ((const void *)className,sizeof(char),i,threadFile);
	fwrite (&num_methods,sizeof(num_methods),1,threadFile);
	for (i=0;i<num_methods;i++) {
	   writeHeader(CONST_LOADMETHOD,&execTime,&clock,threadFile);
	   fwrite (&class_id,sizeof(class_id),1,threadFile);
	   fwrite (&(methods[i].method_id),sizeof(methods[i].method_id),1,threadFile);
	   j = strlen(methods[i].method_name);
	   fwrite (&j,sizeof(j),1,threadFile);
	   fwrite (methods[i].method_name,j,1,threadFile);
	   j = strlen(methods[i].method_signature);
	   fwrite (&j,sizeof(j),1,threadFile);
	   fwrite (methods[i].method_signature,j,1,threadFile);
	}
#endif
#ifdef _FLUSH
	fflush(threadFile);
#endif
}

/*
  MESSAGES of objectAlloc

  CONST_LOADOBJECT|time|clock|envID|threadID|classID|objectID|size
*/
void objectAlloc(JNIEnv *env_id, jobjectID class_ID, jobjectID object_ID, jint size) {
	ThreadHandler * threadHandler;
	jlong clockCalled = getClock();
        getTime();
#ifdef ZLIB
	gzFile threadFile = threadFileOpen(env_id,execTime,clockCalled,&threadHandler);
#else
	FILE * threadFile = threadFileOpen(env_id,execTime,clockCalled,&threadHandler);
#endif

	if (threadHandler!=NULL && usingStartList && !threadHandler->startupEntry) return;

	#ifdef _DEBUG_STACK
	debugStack("objectAlloc", threadHandler->stackStatus);
	#endif

	if (threadHandler!=NULL) {
		int peekValue = peekStack(threadHandler->stackStatus);
		if (peekValue==1) return;
	}

    jobjectID threadId = CALL(GetThreadObject(env_id));
	if (class_ID!=0) {

		struct _classInfo * classInfo = NULL;
		int result=lookupObj(linkedListClasses, class_ID, (void **)&classInfo);
		if (!result) {
			jint ret = CALL(RequestEvent(JVMPI_EVENT_CLASS_LOAD,class_ID));
		} else
		// I need to recall this object
		if (result && classInfo->isLoaded==0) {
			classInfo->isLoaded=2;
			jint ret = CALL(RequestEvent(JVMPI_EVENT_CLASS_LOAD,class_ID));
		}
	}

	/*if (!lookupObj(linkedListThreads, threadId)) {
		fprintf (logfile,"Requesting thread %ld <from objectAlloc>\n",threadId);
		jint ret = CALL(RequestEvent(JVMPI_EVENT_THREAD_START,threadId));
	}*/

	//if (!threadHandler->numberOfIgnoredLevels) {
		writeHeader(CONST_LOADOBJECT,&execTime,&clockCalled,threadFile);
	#ifdef ZLIB
		gzwritelocal (threadFile,&env_id, sizeof (JNIEnv *),"objalloc1");
		gzwritelocal (threadFile,&threadId, sizeof (JNIEnv *),"objalloc2");
		gzwritelocal (threadFile,&class_ID, sizeof (class_ID),"objalloc3");
		gzwritelocal (threadFile,&object_ID, sizeof (object_ID),"objalloc4");
		gzwritelocal (threadFile,&size, sizeof (size),"objalloc5");
	#else
		fwrite (&env_id, sizeof (JNIEnv *), 1, threadFile);
		fwrite (&threadId, sizeof (JNIEnv *), 1, threadFile);
		fwrite (&class_ID, sizeof (class_ID), 1, threadFile);
		fwrite (&object_ID, sizeof (object_ID), 1, threadFile);
		fwrite (&size, sizeof (size), 1, threadFile);
	#endif
	#ifdef _FLUSH
		fflush(threadFile);
	#endif
	//}
}

/*
  MESSAGES of objectFree
  UNLOADOBJECT|time|clock|objectID
*/
void objectFree(JNIEnv *env_id, jobjectID object_ID) {
	ThreadHandler * threadHandler;
	jlong clockCalled = getClock();
	getTime();
        writeHeaderPadrao(CONST_UNLOADOBJECT,&execTime,&clockCalled,out);
	fwrite (&object_ID, sizeof (object_ID), 1, out);
#ifdef _FLUSH
	fflush(out);
#endif
}


/** MESSAGES of GCSTART
    GCSTART|time|clock
*/
void gcstart(JNIEnv *env_id) {
	fprintf (stderr,"JBossProfiler:GCSTART\n");
	ThreadHandler * threadHandler;
	jlong clockCalled = getClock();
	getTime();
    writeHeaderPadrao(CONST_GCSTART,&execTime,&clockCalled,out);
#ifdef _FLUSH
	fflush(threadFile);
#endif
}

/** MESSAGES of GCFINISH
    GCFINISH|time|clock
*/
void gcfinish(JNIEnv *env_id) {
	fprintf (stderr,"JBossProfiler:GCFINISH\n");
	ThreadHandler * threadHandler;
	jlong clockCalled = getClock();
	getTime();
    writeHeaderPadrao(CONST_GCFINISH,&execTime,&clockCalled,out);
#ifdef _FLUSH
	fflush(threadFile);
#endif
}

/*
 MESSAGES of ThreadStart
 THREADSTART|jlong|clock|env_id|thread_ID|sizeOfThreadName|Thread_name
 */
void inline threadStart(JNIEnv *env_id,jobjectID thread_id, char * thread_name ) {
#ifdef DEBUG
    fprintf (logfile,"Thread Start %ld\n",thread_id);
#endif
	ThreadHandler * threadHandler;
	jshort i=0; // general purpose variable
	jlong clockCalled=getClock();
	getTime();
#ifdef ZLIB
	gzFile threadFile = threadFileOpen(env_id,execTime,clockCalled,&threadHandler);
#else
	FILE * threadFile = threadFileOpen(env_id,execTime,clockCalled,&threadHandler);
#endif

    writeHeader(CONST_THREADSTART,&execTime,&clockCalled,threadFile);
#ifdef ZLIB
	gzwritelocal (threadFile,&env_id, sizeof (JNIEnv *),"threadstart1");
	gzwritelocal (threadFile,&thread_id, sizeof (thread_id),"threadstart2");
	i = strlen(thread_name);
	gzwritelocal (threadFile,&i,sizeof(i),"threadstart3");
	gzwritelocal (threadFile,thread_name,sizeof(char)*i,"threadstart4");
#else
	fwrite (&env_id, sizeof (JNIEnv *), 1, threadFile);
	fwrite (&thread_id, sizeof (thread_id), 1, threadFile);
	i = strlen(thread_name);
	fwrite (&i,sizeof(i),1,threadFile);
	fwrite (thread_name,sizeof(char),i,threadFile);
#endif
	addObj(linkedListThreads,thread_id,threadFile);
}


/*
 MESSAGES of ThreadEnd
 THREADEND|jlong|clock|env_id|thread_id
 */
void inline threadEnd(JNIEnv *env_id) {
	// remover as 2 proximas linhas
        jobjectID threadId = CALL(GetThreadObject(env_id));
#ifdef DEBUG
        fprintf (logfile,"ThreadEnd %ld\n",threadId);
#endif

	ThreadHandler * threadHandler;
	jlong clockCalled=getClock();
	getTime();
#ifdef ZLIB
	gzFile threadFile = threadFileOpen(env_id,execTime,clockCalled,&threadHandler);
#else
	FILE * threadFile = threadFileOpen(env_id,execTime,clockCalled,&threadHandler);
#endif

        writeHeader(CONST_THREADEND,&execTime,&clockCalled,threadFile);
#ifdef ZLIB
	gzwritelocal (threadFile,&env_id, sizeof (JNIEnv *),"threadend1");
	gzwritelocal (threadFile,&threadId, sizeof (threadId),"threadend2");
#else
	fwrite (&env_id, sizeof (JNIEnv *), 1,threadFile);
	fwrite (&threadId, sizeof (threadId), 1,threadFile);
#endif

	if (threadHandler!=NULL) {
		if (threadHandler->fileHandler!=NULL) {
#ifdef ZLIB
                        /*int cderro=0;
			cderro=gzflush(threadHandler->fileHandler,Z_FINISH);
			if (cderro!=Z_OK) {
				fprintf (logfile,"Error during gzflush operation - %d\n",cderro);
			}
			cderro=gzclose(threadHandler->fileHandler);
			if (cderro) {
				//fprintf (logfile,"Error during gzflush operation - %ld\n",gzerror(threadHandler->fileHandler,&cderro));
				fprintf (logfile,"Error during gzclose operation - %ld\n",cderro);
			        fflush(logfile);
			}
                        ((FilesInfo*)(threadHandler->fileObjNode))->fileHandler=NULL;
			*/
#else
			fclose(threadHandler->fileHandler);
#endif
		}
		free(threadHandler);
	}
}

/*
 MESSAGES of RawConteredEnter
 CONTENDED_ENTER|jlong|clock|env_id|threadId|<jshort>sizeOfName|char *name|RawId
 */
void rawContendedEnter(JNIEnv * env_id, char * monitorName, JVMPI_RawMonitor idRaw) {
	ThreadHandler * handler;
        jshort i=0;// general purpose local variable
	jlong clockCalled = getClock();
	getTime();
        jobjectID threadId = CALL(GetThreadObject(env_id));
#ifdef ZLIB
	gzFile threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#else
	FILE * threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#endif
        writeHeader(CONST_RAW_CONTENDED_ENTER,&execTime,&clockCalled,threadFile);

#ifdef ZLIB
	gzwritelocal (threadFile,&env_id,sizeof (JNIEnv *),"rawcontendedenter1");
	gzwritelocal (threadFile,&threadId, sizeof (threadId),"rawcontendedenter2");
	i = strlen(monitorName);
	gzwritelocal (threadFile,&i,sizeof(i),"rawcontendedenter3");
	gzwritelocal (threadFile,monitorName,sizeof(char)*i,"rawcontendedenter4");
	gzwritelocal (threadFile,idRaw,sizeof(JVMPI_RawMonitor),"rawcontendedenter5");
#else
	fwrite (&env_id,sizeof (JNIEnv *),1,threadFile);
	fwrite (&threadId, sizeof (threadId), 1,threadFile);
	i = strlen(monitorName);
	fwrite (&i,sizeof(i),1,threadFile);
	fwrite ((const void *)monitorName,sizeof(char),i,threadFile);
	fwrite ((const void *)idRaw,sizeof(JVMPI_RawMonitor),1,threadFile);
#endif
#ifdef _FLUSH
	fflush(threadFile);
#endif
}

/*
 MESSAGES of RawConteredEnter
 CONTENDED_ENTER|jlong|clock|env_id|threadId|<jshort>sizeOfName|char *name|RawId
 */
void rawContendedEntered(JNIEnv * env_id, char * monitorName, JVMPI_RawMonitor idRaw) {
	ThreadHandler * handler;
        jshort i=0;// general purpose local variable
	jlong clockCalled = getClock();
	getTime();
        jobjectID threadId = CALL(GetThreadObject(env_id));
#ifdef ZLIB
	gzFile threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#else
	FILE * threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#endif
        writeHeader(CONST_RAW_CONTENDED_ENTERED,&execTime,&clockCalled,threadFile);

#ifdef ZLIB
	gzwritelocal (threadFile,&env_id,sizeof (JNIEnv *),"rawcontendedentered1");
	gzwritelocal (threadFile,&threadId, sizeof (threadId),"rawcontendedentered2");
	i = strlen(monitorName);
	gzwritelocal (threadFile,&i,sizeof(i),"rawcontendedentered3");
	gzwritelocal (threadFile,monitorName,sizeof(char)*i,"rawcontendedentered4");
	gzwritelocal (threadFile,idRaw,sizeof(JVMPI_RawMonitor),"rawcontendedentered5");
#else
	fwrite (&env_id,sizeof (JNIEnv *),1,threadFile);
	fwrite (&threadId, sizeof (threadId), 1,threadFile);
	i = strlen(monitorName);
	fwrite (&i,sizeof(i),1,threadFile);
	fwrite ((const void *)monitorName,sizeof(char),i,threadFile);
	fwrite ((const void *)idRaw,sizeof(JVMPI_RawMonitor),1,threadFile);
#endif
#ifdef _FLUSH
	fflush(threadFile);
#endif
}


/*
 MESSAGES of RawConteredEnter
 CONTENDED_ENTER|jlong|clock|env_id|threadId|<jshort>sizeOfName|char *name|RawId
 */
void rawContendedExit(JNIEnv * env_id, char * monitorName, JVMPI_RawMonitor idRaw) {
	ThreadHandler * handler;
        jshort i=0;// general purpose local variable
	jlong clockCalled = getClock();
	getTime();
        jobjectID threadId = CALL(GetThreadObject(env_id));
#ifdef ZLIB
	gzFile threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#else
	FILE * threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#endif
        writeHeader(CONST_RAW_CONTENDED_EXIT,&execTime,&clockCalled,threadFile);

#ifdef ZLIB
	gzwritelocal (threadFile,&env_id,sizeof (JNIEnv *),"rawcontendedexit1");
	gzwritelocal (threadFile,&threadId, sizeof (threadId),"rawcontendedexit2");
	i = strlen(monitorName);
	gzwritelocal (threadFile,&i,sizeof(i),"rawcontendedexit3");
	gzwritelocal (threadFile,monitorName,sizeof(char)*i,"rawcontendedexit4");
	gzwritelocal (threadFile,idRaw,sizeof(JVMPI_RawMonitor),"rawcontendedexit5");
#else
	fwrite (&env_id,sizeof (JNIEnv *),1,threadFile);
	fwrite (&threadId, sizeof (threadId), 1,threadFile);
	i = strlen(monitorName);
	fwrite (&i,sizeof(i),1,threadFile);
	fwrite ((const void *)monitorName,sizeof(char),i,threadFile);
	fwrite ((const void *)idRaw,sizeof(JVMPI_RawMonitor),1,threadFile);
#endif
#ifdef _FLUSH
	fflush(threadFile);
#endif
}


/*
 MESSAGES of ConteredEnter
 CONTENDED_ENTER|jlong|clock|env_id|thread_id|object
 */
void contendedEnter(JNIEnv * env_id, jobjectID object) {
	ThreadHandler * handler;
	jlong clockCalled = getClock();
	getTime();
        jobjectID threadId = CALL(GetThreadObject(env_id));
#ifdef ZLIB
	gzFile threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#else
	FILE * threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#endif
    fprintf(stderr,"ContendedEnter ThreadId %ld %ld\n",threadId,execTime);
        writeHeader(CONST_CONTENDED_ENTER,&execTime,&clockCalled,threadFile);
#ifdef ZLIB
	gzwritelocal (threadFile,&env_id,sizeof (JNIEnv *),"contededenter1");
	gzwritelocal (threadFile,&threadId,sizeof (JNIEnv *),"contededenter2");
	gzwritelocal (threadFile,&object,sizeof (object),"contededenter3");
#else
	fwrite (&env_id,sizeof (JNIEnv *),1,threadFile);
	fwrite (&threadId,sizeof (JNIEnv *),1,threadFile);
	fwrite (&object,sizeof (object),1,threadFile);
#endif
#ifdef _FLUSH
	fflush(threadFile);
#endif
}

/*
 MESSAGES of ConteredEntered
 CONTENDED_ENTERED|jlong|clock|env_id|thread_id|objectId
 */
void contendedEntered(JNIEnv * env_id, jobjectID object) {
	ThreadHandler * handler;
	jlong clockCalled = getClock();
	getTime();
        jobjectID threadId = CALL(GetThreadObject(env_id));
#ifdef ZLIB
	gzFile threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#else
	FILE * threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#endif
    fprintf(stderr,"ContendedEnterED ThreadId %ld %ld\n",threadId,execTime);
        writeHeader(CONST_CONTENDED_ENTERED,&execTime,&clockCalled,threadFile);
#ifdef ZLIB
	gzwritelocal (threadFile,&env_id,sizeof (JNIEnv *),"contededentered1");
	gzwritelocal (threadFile,&threadId,sizeof (JNIEnv *),"contededentered2");
	gzwritelocal (threadFile,&object,sizeof (object),"contededentered3");
#else
	fwrite (&env_id,sizeof (JNIEnv *),1,threadFile);
	fwrite (&threadId,sizeof (JNIEnv *),1,threadFile);
	fwrite (&object,sizeof (object),1,threadFile);
#endif
#ifdef _FLUSH
	fflush(threadFile);
#endif
}
/*
 MESSAGES of ConteredExit
 CONTENDED_EXIT|jlong|clock|env_id|thread_id|objectId
*/
void contendedExit(JNIEnv * env_id, jobjectID object) {
	ThreadHandler * handler;
	jlong clockCalled = getClock();
	getTime();
        jobjectID threadId = CALL(GetThreadObject(env_id));
#ifdef ZLIB
	gzFile threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#else
	FILE * threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#endif
    fprintf(stderr,"ContendedEnterExit ThreadId %ld %ld\n",threadId,execTime);
        writeHeader(CONST_CONTENDED_EXIT,&execTime,&clockCalled,threadFile);
#ifdef ZLIB
	gzwritelocal (threadFile,&env_id,sizeof (JNIEnv *),"contededexit1");
	gzwritelocal (threadFile,&threadId,sizeof (JNIEnv *),"contededexit2");
	gzwritelocal (threadFile,&object,sizeof (object),"contededexit3");
#else
	fwrite (&env_id,sizeof (JNIEnv *),1,threadFile);
	fwrite (&threadId,sizeof (JNIEnv *),1,threadFile);
	fwrite (&object,sizeof (object),1,threadFile);
#endif
#ifdef _FLUSH
	fflush(threadFile);
#endif
}




/*
 MESSAGES of ThreadWait
 THREAWAIT|jlong|clock|env_id|thread_id|timeout
 */
void threadWait(JNIEnv * env_id, jobjectID object, jint timeout) {
	ThreadHandler * handler;
	jlong clockCalled = getClock();
	getTime();
#ifdef ZLIB
	gzFile threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#else
	FILE * threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#endif
        writeHeader(CONST_MONITOR_IN,&execTime,&clockCalled,threadFile);
#ifdef ZLIB
	gzwritelocal (threadFile,&env_id,sizeof (JNIEnv *),"threadwait1");
	gzwritelocal (threadFile,&object,sizeof (object),"threadwait2");
#else
	fwrite (&env_id,sizeof (JNIEnv *),1,threadFile);
	fwrite (&object,sizeof (object),1,threadFile);
#endif
#ifdef _FLUSH
	fflush(threadFile);
#endif
}

void threadWaited(JNIEnv * env_id, jobjectID object, jint timeout) {
	ThreadHandler * handler;
	jlong clockCalled = getClock();
	getTime();
#ifdef ZLIB
	gzFile threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#else
	FILE * threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#endif
        writeHeader(CONST_MONITOR_OUT,&execTime,&clockCalled,threadFile);
#ifdef ZLIB
	gzwritelocal (threadFile,&env_id,sizeof (JNIEnv *),"threadwaited1");
	gzwritelocal (threadFile,&object,sizeof (object),"threadwaited2");
#else
	fwrite (&env_id,sizeof (JNIEnv *),1,threadFile);
	fwrite (&object,sizeof (object),1,threadFile);
#endif
#ifdef _FLUSH
	fflush(threadFile);
#endif
}


/*
   MESSAGES of EnterMethod
   ENTRYMETHOD|jlong|clock|env_id|MethodId|ObjectId
*/
void enterMethod(JNIEnv *env_id,jmethodID & methodId, jobjectID & object) {
	ThreadHandler * handler;
        jobjectID threadId = CALL(GetThreadObject(env_id));
	jobjectID classID = CALL(GetMethodClass(methodId));
	struct _classInfo * classInfo = NULL;


	if (!lookupObj(linkedListClasses, classID, (void **)&classInfo)) {
		jint ret = CALL(RequestEvent(JVMPI_EVENT_CLASS_LOAD,classID));
		lookupObj(linkedListClasses, classID, (void **)&classInfo);
	}

	if (classInfo!=NULL && classInfo->isLoaded==CLASS_UNLOADED) {
	    classInfo->isLoaded==CLASS_NEEDS_LOAD;
		lookupObj(linkedListClasses, classID, (void **)&classInfo);
	}



#ifdef COUNT_METHODS
        enterMethods++;
#endif

	jlong clockCalled = getClock();

	getTime();
#ifdef ZLIB
	gzFile threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#else
	FILE * threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#endif


	/*if (classInfo!=NULL && classInfo->isInIgnoreList) {
		handler->numberOfIgnoredLevels++;
	} */

	// push status
	if (classInfo!=NULL) {
		if (classInfo->isInStartList) {
			if (handler->startupEntry<=0){
				handler->startupEntry=1;
			}
			else {
				handler->startupEntry++;
			}
			pushStack(handler->stackStatus,IN_START_LIST);
		}
	}

	if (!(usingStartList && !handler->startupEntry)) {
		#ifdef _DEBUG_STACK
		debugStack("enterMethod", handler->stackStatus);
		#endif

		if (classInfo==NULL || !classInfo->isInIgnoreList || classInfo->isInIncludeList ) {

			// If in startupmode, evedything has to be cathered
			if (classInfo!=NULL && classInfo->isLoaded==0) {
				classInfo->isLoaded=2;
				jint ret = CALL(RequestEvent(JVMPI_EVENT_CLASS_LOAD,classID));
			}
			writeHeader(CONST_ENTERMETHOD,&execTime,&clockCalled,threadFile);
		#ifdef ZLIB
			gzwritelocal (threadFile,&env_id,sizeof (JNIEnv *),"entermethod1");
			gzwritelocal (threadFile,&threadId,sizeof (threadId),"entermethod2");
			gzwritelocal (threadFile,&classID,sizeof (classID),"entermethod3");
			gzwritelocal (threadFile,&methodId,sizeof (methodId),"entermethod4");
			gzwritelocal (threadFile,&object,sizeof (object),"entermethod5");
		#else
			fwrite (&env_id,sizeof (JNIEnv *),1,threadFile);
			fwrite (&threadId,sizeof (threadId),1,threadFile);
			fwrite (&classID,sizeof (classID),1,threadFile);
			fwrite (&methodId,sizeof (methodId),1,threadFile);
			fwrite (&object,sizeof (object),1,threadFile);
		#endif
		#ifdef _FLUSH
			fflush(threadFile);
		#endif
		}
	}
}

/*
   MESSAGES of ExitMethod
   EXITMETHOD|jlong|clock|env_id|MethodId
*/
void exitMethod(JNIEnv *env_id,jmethodID & methodId) {
#ifdef COUNT_METHODS
        exitMethods++;
#endif
	ThreadHandler * handler;
        jobjectID threadId = CALL(GetThreadObject(env_id));
	jlong clockCalled = getClock();
	getTime();
#ifdef ZLIB
	gzFile threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#else
	FILE * threadFile = threadFileOpen(env_id,execTime,clockCalled,&handler);
#endif

	jobjectID classID = CALL(GetMethodClass(methodId));
	struct _classInfo * classInfo;
	if (!lookupObj(linkedListClasses, classID, (void **)&classInfo)) {
		jint ret = CALL(RequestEvent(JVMPI_EVENT_CLASS_LOAD,classID));
		lookupObj(linkedListClasses, classID, (void **)&classInfo);
	}

	if (classInfo!=NULL && classInfo->isLoaded==CLASS_UNLOADED) {
	    classInfo->isLoaded==CLASS_NEEDS_LOAD;
		lookupObj(linkedListClasses, classID, (void **)&classInfo);
	}


	if (!(usingStartList && !handler->startupEntry)) {
		#ifdef _DEBUG_STACK
		debugStack("exitMethod ", handler->stackStatus);
		#endif

		if (classInfo==NULL || !classInfo->isInIgnoreList || classInfo->isInIncludeList ) {
			if (classInfo!=NULL) {
				popStack(handler->stackStatus);
			}


			writeHeader(CONST_EXITMETHOD,&execTime,&clockCalled,threadFile);
			#ifdef ZLIB
				gzwritelocal (threadFile,&env_id,sizeof (JNIEnv *),"methodexit1");
				gzwritelocal (threadFile,&threadId,sizeof (threadId),"methodexit2");
				gzwritelocal (threadFile,&methodId,sizeof (methodId),"methodexit3");
			#else
				fwrite (&env_id,sizeof (JNIEnv *),1,threadFile);
				fwrite (&threadId,sizeof (threadId),1,threadFile);
				fwrite (&methodId,sizeof (methodId),1,threadFile);
			#endif

			#ifdef _FLUSH
				fflush(threadFile);
			#endif
		}
		if (classInfo!=NULL && classInfo->isInStartList) {
			handler->startupEntry--;
		}

	}

	/* if (classInfo!=NULL && classInfo->isInIgnoreList) {
		handler->numberOfIgnoredLevels--;
		if (handler->numberOfIgnoredLevels<0) handler->numberOfIgnoredLevels=0;
	} */

}

void inline flushAllFiles(){
#ifdef ZLIB
    gzwritelock=1; // nao podem mais acontecer nenhuma escria
#endif
   std::vector<void *>::iterator p;

   fprintf (logfile,"**************** files debug information *********************\n");
   for (p=linkedListFiles.begin();p!=linkedListFiles.end();p++) {
        FilesInfo* fileInfo = (FilesInfo*)(*p);
	if (fileInfo->fileHandler!=NULL) {
#ifdef ZLIB
		    gzFile threadFile = (gzFile) fileInfo->fileHandler;
                        int cderro=0;
			cderro=gzclose(threadFile);
			if (cderro) {
				fprintf (logfile,"Error during gzclose operation(flushAllFiles) - %s\n",gzerror(threadFile,&cderro));
				fflush(logfile);
			}

#else
		    FILE * threadFile = (FILE *) fileInfo->fileHandler;
		    fflush(threadFile);
#endif
	}
    }
    fflush(logfile);
    fflush(out);
}

void removeProfiler(short isShutdown) {
     if (!isShutdown) {
          CALL(RunGC)();
     }
     profilerRunning=-1;
     fprintf (logfile,"Stopping DataGathering\n");
     fprintf (stderr,"Stopping DataGathering\n");
    // enabling class load event notification
    jvmpi_interface->DisableEvent(JVMPI_EVENT_CLASS_LOAD, NULL);
    //jvmpi_interface->DisableEvent(JVMPI_EVENT_CLASS_UNLOAD, NULL);
    jvmpi_interface->DisableEvent(JVMPI_EVENT_METHOD_ENTRY2, NULL);
    jvmpi_interface->DisableEvent(JVMPI_EVENT_METHOD_EXIT, NULL);

    if (profileMemory)
    {
    	jvmpi_interface->DisableEvent(JVMPI_EVENT_OBJECT_ALLOC, NULL);
    	jvmpi_interface->DisableEvent(JVMPI_EVENT_OBJECT_FREE, NULL);
    }

    jvmpi_interface->DisableEvent(JVMPI_EVENT_GC_START, NULL);
    jvmpi_interface->DisableEvent(JVMPI_EVENT_GC_FINISH, NULL);
    jvmpi_interface->DisableEvent(JVMPI_EVENT_MONITOR_WAIT, NULL);
    jvmpi_interface->DisableEvent(JVMPI_EVENT_MONITOR_WAITED, NULL);

    jvmpi_interface->DisableEvent(JVMPI_EVENT_MONITOR_CONTENDED_ENTER, NULL);
    jvmpi_interface->DisableEvent(JVMPI_EVENT_MONITOR_CONTENDED_ENTERED, NULL);
    jvmpi_interface->DisableEvent(JVMPI_EVENT_MONITOR_CONTENDED_EXIT, NULL);


    /*jvmpi_interface->DisableEvent(JVMPI_EVENT_MONITOR_CONTENDED_ENTER, NULL);
    jvmpi_interface->DisableEvent(JVMPI_EVENT_MONITOR_CONTENDED_ENTERED, NULL);
    jvmpi_interface->DisableEvent(JVMPI_EVENT_MONITOR_CONTENDED_EXIT, NULL);

    jvmpi_interface->DisableEvent(JVMPI_EVENT_RAW_MONITOR_CONTENDED_ENTER, NULL);
    jvmpi_interface->DisableEvent(JVMPI_EVENT_RAW_MONITOR_CONTENDED_ENTERED, NULL);
    jvmpi_interface->DisableEvent(JVMPI_EVENT_RAW_MONITOR_CONTENDED_EXIT, NULL); */

    jvmpi_interface->DisableEvent(JVMPI_EVENT_THREAD_START, NULL);
    jvmpi_interface->DisableEvent(JVMPI_EVENT_THREAD_END, NULL);

#ifdef ZLIB
    gzwritelock=1;
#endif

    //jlong target = sysTimeMillis() + (jlong)10000;
    // esperando 10 segundos para que todos os eventos acabem
    //while (target>sysTimeMillis());
    flushAllFiles();
    
    jvmpi_interface->RawMonitorDestroy(list_mutex_t);

//    debugFiles();
}


void pauseProfiler() {
     fprintf (logfile,"JBossProfiler: Pausing DataGathering\n");
     fflush(logfile);
     fprintf (stderr,"JBossProfiler: Pausing DataGathering\n");
    // enabling class load event notification
    jvmpi_interface->DisableEvent(JVMPI_EVENT_CLASS_LOAD, NULL);
    //jvmpi_interface->DisableEvent(JVMPI_EVENT_CLASS_UNLOAD, NULL);
    jvmpi_interface->DisableEvent(JVMPI_EVENT_METHOD_ENTRY2, NULL);
    jvmpi_interface->DisableEvent(JVMPI_EVENT_METHOD_EXIT, NULL);

    if (profileMemory)
    {
      jvmpi_interface->DisableEvent(JVMPI_EVENT_OBJECT_ALLOC, NULL);
      jvmpi_interface->DisableEvent(JVMPI_EVENT_OBJECT_FREE, NULL);
    }

    jvmpi_interface->DisableEvent(JVMPI_EVENT_GC_START, NULL);
    jvmpi_interface->DisableEvent(JVMPI_EVENT_GC_FINISH, NULL);
    //jvmpi_interface->DisableEvent(JVMPI_EVENT_MONITOR_WAIT, NULL);
    //jvmpi_interface->DisableEvent(JVMPI_EVENT_MONITOR_WAITED, NULL);

    //jvmpi_interface->DisableEvent(JVMPI_EVENT_MONITOR_CONTENDED_ENTER, NULL);
    //jvmpi_interface->DisableEvent(JVMPI_EVENT_MONITOR_CONTENDED_ENTERED, NULL);
    //jvmpi_interface->DisableEvent(JVMPI_EVENT_MONITOR_CONTENDED_EXIT, NULL);

    //jvmpi_interface->DisableEvent(JVMPI_EVENT_RAW_MONITOR_CONTENDED_ENTER, NULL);
    //jvmpi_interface->DisableEvent(JVMPI_EVENT_RAW_MONITOR_CONTENDED_ENTERED, NULL);
    //jvmpi_interface->DisableEvent(JVMPI_EVENT_RAW_MONITOR_CONTENDED_EXIT, NULL);

    jvmpi_interface->DisableEvent(JVMPI_EVENT_THREAD_START, NULL);
    jvmpi_interface->DisableEvent(JVMPI_EVENT_THREAD_END, NULL);

}

void initProfiler() {
     profilerRunning=1;

     fprintf (logfile,"Initializing DataGathering\n");
     fflush(logfile);
     fprintf (stderr,"JBossProfiler: Initializing DataGathering\n");
    // enabling class load event notification
    jvmpi_interface->EnableEvent(JVMPI_EVENT_CLASS_LOAD, NULL);
    //jvmpi_interface->EnableEvent(JVMPI_EVENT_CLASS_UNLOAD, NULL);
    jvmpi_interface->EnableEvent(JVMPI_EVENT_METHOD_ENTRY2, NULL);
    jvmpi_interface->EnableEvent(JVMPI_EVENT_METHOD_EXIT, NULL);

    if (profileMemory)
    {
	    jvmpi_interface->EnableEvent(JVMPI_EVENT_OBJECT_ALLOC, NULL);
	    jvmpi_interface->EnableEvent(JVMPI_EVENT_OBJECT_FREE, NULL);
	}

    jvmpi_interface->EnableEvent(JVMPI_EVENT_GC_START, NULL);
    jvmpi_interface->EnableEvent(JVMPI_EVENT_GC_FINISH, NULL);
    //jvmpi_interface->EnableEvent(JVMPI_EVENT_MONITOR_WAIT, NULL);
    //jvmpi_interface->EnableEvent(JVMPI_EVENT_MONITOR_WAITED, NULL);

    jvmpi_interface->EnableEvent(JVMPI_EVENT_MONITOR_CONTENDED_ENTER, NULL);
    jvmpi_interface->EnableEvent(JVMPI_EVENT_MONITOR_CONTENDED_ENTERED, NULL);
    //jvmpi_interface->EnableEvent(JVMPI_EVENT_MONITOR_CONTENDED_EXIT, NULL);

    //jvmpi_interface->EnableEvent(JVMPI_EVENT_RAW_MONITOR_CONTENDED_ENTER, NULL);
    //jvmpi_interface->EnableEvent(JVMPI_EVENT_RAW_MONITOR_CONTENDED_ENTERED, NULL);
    //jvmpi_interface->EnableEvent(JVMPI_EVENT_RAW_MONITOR_CONTENDED_EXIT, NULL);

    jvmpi_interface->EnableEvent(JVMPI_EVENT_JVM_SHUT_DOWN, NULL);

    jvmpi_interface->EnableEvent(JVMPI_EVENT_THREAD_START, NULL);
    jvmpi_interface->EnableEvent(JVMPI_EVENT_THREAD_END, NULL);

    list_mutex_t= jvmpi_interface->RawMonitorCreate("_thread_list_files");



}

void changeProfiller() {
	  if (profilerRunning) {
                  fprintf (stderr,"JBossProfiler: Singal for removeProfiler\n");
		  removeProfiler(FALSE);
	  } else {
                  fprintf (stderr,"JBossProfiler: Singal for initProfiler\n");
		  initProfiler();
          }
}


// function for handling event notification
void notifyEvent(JVMPI_Event *event) {
if (profilerRunning<0) return;
// check da inicializacao do profiler por socket

if (!profilerRunning && event->event_type==JVMPI_EVENT_METHOD_ENTRY2) return;


#ifdef COUNT_METHODS
  static int cont=0;
  if ((cont++)%1000==0) {
     fprintf (logfile,"Enter = %ld Exit=%ld\n",enterMethods,exitMethods);
  }
#endif
  switch(event->event_type) {
  case JVMPI_EVENT_CLASS_UNLOAD:
      fprintf (stderr,"JBossProfiler: Class Unloading\n");
      break;
  case JVMPI_EVENT_CLASS_LOAD|JVMPI_REQUESTED_EVENT:
  case JVMPI_EVENT_CLASS_LOAD:
    loadClass(event->env_id,
              event->u.class_load.class_id,
              (char *)event->u.class_load.class_name,
              event->u.class_load.num_methods,
              event->u.class_load.methods);
    break;

  case JVMPI_EVENT_METHOD_ENTRY2:
    enterMethod(event->env_id,event->u.method_entry2.method_id,event->u.method_entry2.obj_id);
    break;

  case JVMPI_EVENT_METHOD_EXIT:
    exitMethod(event->env_id,event->u.method.method_id);
    break;

  case JVMPI_EVENT_OBJECT_ALLOC:
    if (event->u.obj_alloc.is_array==JVMPI_NORMAL_OBJECT) {
         objectAlloc(event->env_id,
	             event->u.obj_alloc.class_id,
		     event->u.obj_alloc.obj_id,
		     event->u.obj_alloc.size);
    }
    break;

  case JVMPI_EVENT_OBJECT_FREE:
    objectFree(event->env_id,event->u.obj_free.obj_id);
    break;

  case JVMPI_EVENT_GC_START:
    gcstart(event->env_id);
    break;
  case JVMPI_EVENT_GC_FINISH:
    gcfinish(event->env_id);
    break;

  case JVMPI_EVENT_THREAD_START|JVMPI_REQUESTED_EVENT:
  case JVMPI_EVENT_THREAD_START:
    threadStart(event->env_id,event->u.thread_start.thread_id,event->u.thread_start.thread_name);
     break;

  case JVMPI_EVENT_THREAD_END:
     threadEnd(event->env_id);
     break;
  case JVMPI_EVENT_MONITOR_WAIT:
     threadWait(event->env_id, event->u.monitor_wait.object, event->u.monitor_wait.timeout);
     break;
  case JVMPI_EVENT_MONITOR_WAITED:
     threadWaited(event->env_id, event->u.monitor_wait.object, event->u.monitor_wait.timeout);
     break;

  case JVMPI_EVENT_MONITOR_CONTENDED_ENTER:
     contendedEnter(event->env_id, event->u.monitor.object);
     break;
  case JVMPI_EVENT_MONITOR_CONTENDED_ENTERED:
     contendedEntered(event->env_id, event->u.monitor.object);
     break;
  case JVMPI_EVENT_MONITOR_CONTENDED_EXIT:
     contendedExit(event->env_id, event->u.monitor.object);
     break;

  case JVMPI_EVENT_RAW_MONITOR_CONTENDED_ENTER:
     rawContendedEnter(event->env_id, (char *)event->u.raw_monitor.name, event->u.raw_monitor.id);
     break;
  case JVMPI_EVENT_RAW_MONITOR_CONTENDED_ENTERED:
     rawContendedEntered(event->env_id,(char *) event->u.raw_monitor.name, event->u.raw_monitor.id);
     break;
  case JVMPI_EVENT_RAW_MONITOR_CONTENDED_EXIT:
     rawContendedExit(event->env_id, (char *)event->u.raw_monitor.name, event->u.raw_monitor.id);
     break;

  case JVMPI_EVENT_DATA_DUMP_REQUEST:
	  if (profilerRunning) {
		  removeProfiler(FALSE);
	  } else {
		  initProfiler();
          }
     break;
    case JVMPI_EVENT_JVM_INIT_DONE:
        if(wakeupOnStartup) {
            initProfiler();
        }
	#ifdef USE_SOCKETS
	    if (usingSockets) {
	       startConsoleCheck(parametroSocket,pid);
	       //jvmpi_interface->EnableEvent(JVMPI_EVENT_METHOD_ENTRY2, NULL);
	    }
	#endif

        break;
    case JVMPI_EVENT_JVM_SHUT_DOWN:
      fprintf (stderr,"\n\nJBossProfiler: Stopping profiler by shutdown\n");
	  if (profilerRunning) {
		  removeProfiler(TRUE);
	  }
	  break;
  default:
     fprintf (logfile,"JBossProfiler: Invalid Event in the switch -> %d\n",event->event_type);
  }

  if (profilerRunning==-1) {
      fflush(logfile);
  }

#ifdef _FLUSH
	fflush(out);
#endif
}


char ** divideStringsByCharacter(char * parameter, char characterToDive, int * numberOfResultStrings) {
	int len = strlen(parameter);
	int nComma=0;
	for (int i=0;i<len;i++) {
		if (parameter[i]==characterToDive) nComma++;
	}

	if (nComma==0) {
		char ** result = (char **)malloc(sizeof(char *));
		*numberOfResultStrings=1;
		*result=parameter;

		return result;
	}

	char ** result =(char **) malloc(sizeof (char *) * (nComma +1));

	int lastPos=0;
	int quantity=0;

	for (int i=0;i<len;i++) {
		if (parameter[i]==characterToDive) {
			result[quantity++] = parameter + lastPos;
			lastPos=i+1;
			parameter[i]=0;
		}
	}

	result[quantity++] = parameter + lastPos;
	*numberOfResultStrings = quantity;
	return result;
}


// lookup for '=' in a string, and verifies if this is a valid parameter
int isValidParameter(char * parameter)
{
    int sizeOfParameter = strlen(parameter);
    // I could have used some findCharAt function present at string.h, but I didn't have time to research for it. It would be pretty easy, but I didn't have access to any documentation when I've done this.
    // This is perfecatly refactarable, so if you have a patch and feel kind of bothered by this lookup loop... pleeeeeeeease send me the patch :-)
    int equalsPosition=0;
    for (;equalsPosition<sizeOfParameter;equalsPosition++)
    {
       if (parameter[equalsPosition]=='=')
       {
          break;
       }
    }

    if (equalsPosition>=sizeOfParameter || equalsPosition>(sizeOfParameter-1)) // tests if '=' char wasnn't found or if '=' is the latest char
    {
       //fprintf (stderr,"parameter %s didn't have '='\n",parameter);
       return 1;
    }

    char * secondParameter = parameter + equalsPosition + 1;

    //int maxParameters=7;
    int maxParameters=8;
    //char * validParameters[] ={"wakeupOnStartup","uniqueNames","memory","ignore","start","include","socket"};
    char * validParameters[] ={"wakeupOnStartup","uniqueNames","memory","ignore","start","include","socket","tracer"};

    int parameterNumber=0;
    for (parameterNumber=0;parameterNumber<maxParameters;parameterNumber++)
    {
        if (strncmp(validParameters[parameterNumber],parameter,equalsPosition)==0)
        {
           break;
        }
    }

    if (parameterNumber>=maxParameters)
    {
    	//fprintf (stderr,"didn't find %s",parameter);
    	return 0;
    }


    if (parameterNumber<=2) // location of boolean parameters
    {
        if (!(strcmp(secondParameter,"true")==0 || strcmp(secondParameter,"false")==0))
        {
           //fprintf (stderr,"Invalid value %s at %s\n",parameter,secondParameter);
           return 0;
        }
    }

    return 1;


}

// main - ponto principal de entrada
// profiler agent entry point
extern "C" {
  JNIEXPORT jint JNICALL JVM_OnLoad(JavaVM *jvm, char *options, void *reserved) {
    // get jvmpi interface pointer
#ifdef WINDOWS
    fprintf (stderr,"Running process on Windows %ld\n",_getpid());
    pid = _getpid();
    getTime();
    startTime=execTime;
#else
    fprintf (stderr,"Running process %ld\n",getpid());
    pid = getpid();
    getTime();
    startTime=execTime;
#endif

     profilerRunning=0;


     int n=0;
     char ** parameterStrings = divideStringsByCharacter(options,',',&n);

     int uniqueNames=0;
     for (int i=0;i<n;i++) {
        if (!isValidParameter(parameterStrings[i]))
        {
           fprintf (stderr,"Invalid parameters passed to the profiler. Can't start JVM becuase of that, please fix %s\n",parameterStrings[i]);
           exit(-1);
        }

	    if (strcmp(parameterStrings[i],"wakeupOnStartup=true")==0) {
	       fprintf (stderr,"The profiler will be activated after the JVM is loaded\n");
	       wakeupOnStartup=true;
	    }

	    if (strcmp(parameterStrings[i],"uniqueNames=true")==0) {
	       pid=startTime;
#ifdef WINDOWS
	       fprintf (stderr,"Using uniqueName = %I64d\n",pid);
#else
	       fprintf (stderr,"Using uniqueName = %lld\n",pid);
#endif
	    }

	    if (strcmp(parameterStrings[i],"memory=false")==0) {
	       profileMemory=0;
	       fprintf (stderr,"JBossProfiler: Disabling memory events\n");
	    }

            //for tracer
            if (strcmp(parameterStrings[i],"tracer=true")==0) {
               transactionTracer=1;
               fprintf (stderr,"JBoss Tracer: Enabling Exceptions/Errors\n");
            }

     }


#ifdef USE_SOCKETS
    for (int i=0;i<n;i++) {
	    if (strncmp(parameterStrings[i],"socket=",7)==0) {
               usingSockets=1;
	       strcpy (parametroSocket,parameterStrings[i]+7);
	    }
    }

    if (usingSockets) {
       fprintf (stderr,"Using sockets for start/stop control at %s\n",parametroSocket);
    }
#endif


    //time(&startTime);
    startTime=sysTimeMillis();
    //linkedListClasses.root=linkedListClasses.end=NULL;
    //linkedListThreads.root=linkedListThreads.end=NULL;
    if ((jvm->GetEnv((void **)&jvmpi_interface, JVMPI_VERSION_1)) < 0) {
      fprintf(stderr, "dpInspector> error in obtaining jvmpi interface pointer\n");
      return JNI_ERR;
    }

    if ((jvm->GetEnv((void **)&jni_interface, JNI_VERSION_1_2)) < 0) {
      fprintf(stderr, "dpInspector> error in obtaining JNI interface pointer\n");
      return JNI_ERR;
    }

    if (options==NULL) {
	    fprintf (stderr,"Usage of SPYServer:\n");
	    fprintf (stderr,"java -XrundpInspector:\"log directory\"\n");
	    jvmpi_interface->ProfilerExit(-2);
    }

    char strFileLog[256];
#ifdef WINDOWS
    sprintf (logFileDirectory,"%s\\",options);
    sprintf (strFileLog,"%slog_spyserver_%I64d.txt",logFileDirectory,pid);
#else
    sprintf (logFileDirectory,"%s/",options);
    sprintf (strFileLog,"%slog_spyserver_%lld.txt",logFileDirectory,pid);
#endif

    logfile = fopen(strFileLog,"wb");
    if (logfile==NULL) {
	    fprintf (stderr,"Cannot open file %s. Please check you directory name\n",strFileLog);
	    exit(-1);
    }

    loadIgnoreList(n,parameterStrings);


    log_start = startTime;
#ifdef WINDOWS
    sprintf (mainLogFileName,"%sserverspy_%I64d_main_%I64d.log", logFileDirectory,pid, log_start);
#else
    sprintf (mainLogFileName,"%sserverspy_%lld_main_%lld.log", logFileDirectory,pid, log_start);
#endif

    out = fopen (mainLogFileName,"wb");

    //addFileOnLinkedList(mainLogFileName,out);
    if (out==NULL) {
	    fprintf (logfile,"Isn't possible open file %s\n",mainLogFileName);
	    jvmpi_interface->ProfilerExit(-2);
    }


    writeMainHeader();

    // initialize jvmpi interface
    jvmpi_interface->NotifyEvent = notifyEvent;

#ifndef FULLPROFILLER
    jvmpi_interface->EnableEvent(JVMPI_EVENT_DATA_DUMP_REQUEST, NULL);
#endif
    //jvmpi_interface->EnableEvent(JVMPI_EVENT_THREAD_START, NULL);
    //jvmpi_interface->EnableEvent(JVMPI_EVENT_CLASS_LOAD, NULL);
    //jvmpi_interface->EnableEvent(JVMPI_EVENT_THREAD_END, NULL);
    jvmpi_interface->EnableEvent(JVMPI_EVENT_JVM_INIT_DONE, NULL);


#ifdef FULLPROFILLER
    initProfiler();
#endif

    fflush(out);

    free(parameterStrings);

    return JNI_OK;
  }
}


void printMessageError() {
       fprintf (stderr,"Error: Requires initialization with -XrunjbossInspector:<directory>,parameters\n");
       fprintf (stderr,"Read the documentation about JBossProfiler\n");
}

JNIEXPORT void JNICALL Java_org_jboss_profiler_threadcheck_StartupProfilerCheck_startProfilerInternal
(JNIEnv * penv, jclass pclass) {
   if (profilerRunning>=0) {
	   initProfiler();
   } else {
       printMessageError();
   }
   // todo: exception if not initialized
}

JNIEXPORT void JNICALL Java_org_jboss_profiler_threadcheck_StartupProfilerCheck_stopProfilerInternal
(JNIEnv * penv, jclass pclass) {
   if (profilerRunning>=0) {
	   removeProfiler(FALSE);
   } else {
      printMessageError();
   }
}

JNIEXPORT void JNICALL Java_org_jboss_profiler_threadcheck_StartupProfilerCheck_pauseProfilerInternal
(JNIEnv * penv, jclass pclass) {
   if (profilerRunning>=0) {
	   pauseProfiler();
   } else {
      printMessageError();
   }
}



// rotina que ira conectar com a console
void startConsoleCheck(char * socketParameter, jlong pid) {
     jclass checkClass=jni_interface->FindClass("org/jboss/profiler/threadcheck/StartupProfilerCheck");
     if (checkClass==NULL) {
            fprintf (stderr,"\n***********************\nFatalError: Cannot find org.jboss.profiler.threadcheck.StartupProfilerCheck.initCheck(String,int)\n");
            fprintf (stderr,"Check you classpath for profilerConsole.jar\n");
	     return;
     }

     jmethodID metodoInit=jni_interface->GetStaticMethodID(checkClass,"initCheck","(Ljava/lang/String;L)V");
     if (metodoInit==NULL) {
        fprintf (stderr,"\n***********************\nFatalError: Cannot find org/jboss/profiler/threadcheck/StartupProfilerCheck.initCheck(String,int)\n");
        fprintf (stderr,"Check you classpath for profilerConsole.jar\n");
        return;
     }

     jstring strParameter = jni_interface->NewStringUTF(socketParameter);
     jlong jlongPid = pid;
     jni_interface->CallStaticVoidMethod(checkClass,metodoInit,strParameter,jlongPid);

}
