/* -*- Mode: C; c-file-style: "gnu" -*-
   jvmdithr.c -- JVMDI Thread Execution Functions
   Created: Hernan Otero <hernan_otero@bigfoot.com>, 18-Jul-1998.
 */
/*
  This file is part of Japhar, the GNU Virtual Machine for Java Bytecodes.
  Japhar is a project of The Hungry Programmers, GNU, and OryxSoft.

  Copyright (C) 1998, 1999 The Hungry Programmers

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library 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
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "jvmdiint.h"
#include "interp.h"
#include "objects.h"
#include "log.h"

#include <stdlib.h>

#define MYLOG "JVMDI"

JNIEXPORT jvmdiError JNICALL
JVMDI_GetThreadStatus(JNIEnv *env,
		      jthread thread,
		      jint *statusPtr)
{
  JThreadInfo *thread_info;

  if (env == NULL
      || thread == NULL
      || statusPtr == NULL)
    return JVMDI_ERROR_NULL_POINTER;

  thread_info = (JThreadInfo*)NSA_GetNativeState(thread);
  if (thread_info == NULL)
    return JVMDI_ERROR_INVALID_THREAD;
  
  switch (STATE(thread_info)) {
  case STATE_INTERRUPTED:
    /*
     *
     */
    *statusPtr = JVMDI_THREAD_STATUS_RUNNING;
    break;
  case STATE_RUNNING:
    /*
     * Thread is runnable.
     */
    *statusPtr = JVMDI_THREAD_STATUS_RUNNING;
    break;
  case STATE_FINISHED:
    /*
     * Thread is waiting to die.
     */
    *statusPtr = JVMDI_THREAD_STATUS_ZOMBIE;
    break;
  case STATE_SUSPENDED:
    /*
     * Thread suspended. (Thread.suspend(), JVM_Suspend(), or
     * JVMDI_Suspend().) 
     */
    *statusPtr = JVMDI_THREAD_STATUS_SUSPENDED;
    break;
#if 0
    /* XXX need to consider these cases too! */
    /*
     * Thread sleeping. (Thread.sleep() or JVM_Sleep().) 
     */
    *statusPtr = JVMDI_THREAD_STATUS_SLEEPING
      break;

    /*
     * Synchronization block. 
     */
    *statusPtr = JVMDI_THREAD_STATUS_MONITOR 
      break;

    /*
     * Thread waiting. (Thread.wait() or JVM_MonitorWait().) 
     */
    *statusPtr = JVMDI_THREAD_STATUS_WAIT 
      break;

    /*
     * Thread at breakpoint.
     */
    *statusPtr = JVMDI_THREAD_STATUS_BREAK;
    break;
#endif
  default:
    /*
     * Status unknown
     */
    *statusPtr = JVMDI_THREAD_STATUS_UNKNOWN;
    break;
  }
  return JVMDI_ERROR_NONE;
}

JNIEXPORT jvmdiError JNICALL
JVMDI_GetAllThreads(JNIEnv *env, jint *threadsCountPtr,
                    jthread **threadsPtr)
{
  int num = 0;
  HungryJNIEnv *head_env = ((HungryJNIEnv*)env)->_vm->_envs;

  if (env == NULL
      || threadsPtr == NULL
      || threadsCountPtr == NULL)
    return JVMDI_ERROR_NULL_POINTER;

  while (head_env)
    {
      num++;
      head_env = head_env->next;
    }

  *threadsCountPtr = num;
  *threadsPtr = (jthread*)malloc(sizeof(jthread) * num);

  if (*threadsPtr == NULL)
    return JVMDI_ERROR_OUT_OF_MEMORY;

  head_env = ((HungryJNIEnv*)env)->_vm->_envs;
  num = 0;
  while (head_env)
    {
      (*threadsPtr)[ num ] = head_env->_java_info->java_thread;
      head_env = head_env->next;
    }

  return JVMDI_ERROR_NONE;
}

JNIEXPORT jvmdiError JNICALL
JVMDI_SuspendThread(JNIEnv *env,
		    jthread thread)
{
  JThreadInfo *thread_info;

  if (env == NULL
      || thread == NULL)
    return JVMDI_ERROR_NULL_POINTER;

  thread_info = NSA_GetNativeState(thread);
  if (thread_info == NULL)
    return JVMDI_ERROR_INVALID_THREAD;

  /* the thread cant be suspended for this operation. */
  if (STATE(thread_info) == STATE_SUSPENDED) {
    return JVMDI_ERROR_THREAD_SUSPENDED;
  }

  /* XXX should check for JVMDI_ERROR_DEAD_VM */

  JAVARLOG1(MYLOG, 1, "suspending thread(%p)\n", thread);
#if 0
  suspend_thread((japhar_obj)thread, thread_info);
#endif

  STATE(thread_info) = STATE_SUSPENDED;

  return JVMDI_ERROR_NONE;
}

JNIEXPORT jvmdiError JNICALL
JVMDI_ResumeThread(JNIEnv *env,
		   jthread thread)
{
  JThreadInfo *thread_info;

  if (env == NULL
      || thread == NULL)
    return JVMDI_ERROR_NULL_POINTER;

  thread_info = (JThreadInfo*)NSA_GetNativeState(thread);
  if (thread_info == NULL)
    return JVMDI_ERROR_INVALID_THREAD;

  /* the thread must be suspended for this operation. */
  if (STATE(thread_info) != STATE_SUSPENDED)
    return JVMDI_ERROR_THREAD_NOT_SUSPENDED;

  /* XXX should check for JVMDI_ERROR_DEAD_VM */

  JAVARLOG1(MYLOG, 1, "resuming thread(%p)\n", thread);
#if 0
  resume_thread((japhar_obj)thread, thread_info);
#endif

  STATE(thread_info) = STATE_RUNNING;

  return JVMDI_ERROR_NONE;
}

JNIEXPORT jvmdiError JNICALL
JVMDI_StopThread(JNIEnv *env, jthread thread, jobject exception)
{
  return JVMDI_ERROR_NOT_IMPLEMENTED;
}

JNIEXPORT jvmdiError JNICALL
JVMDI_InterruptThread(JNIEnv *env, jthread thread)
{
  return JVMDI_ERROR_NOT_IMPLEMENTED;
}

JNIEXPORT jvmdiError JNICALL
JVMDI_SetSingleStep(JNIEnv *env,
		    jthread thread,
		    jboolean shouldStep)
{
  JThreadInfo *thread_info;

  if (env == NULL
      || thread == NULL)
    return JVMDI_ERROR_NULL_POINTER;

  thread_info = (JThreadInfo*)NSA_GetNativeState(thread);
  if (thread_info == NULL)
    return JVMDI_ERROR_INVALID_THREAD;

  /* the thread must be suspended for this operation. */
  if (STATE(thread_info) != STATE_SUSPENDED)
    return JVMDI_ERROR_THREAD_NOT_SUSPENDED;

  /* XXX should check for JVMDI_ERROR_DEAD_VM */

  /* XXX should actually do something here! */
  fprintf(stderr, "set single step on thread (%p) ignored - not yet implemented\n", thread);

  return JVMDI_ERROR_NONE;
}
