/******************************************************************************
    Copyright (c) 1998-2000 CoWare, Inc.    ALL RIGHTS RESERVED

The following code is derived, directly or indirectly, from the SystemC
source code released by Synopsys, Inc Copyright (c) 1996-2001, Synopsys,
Inc., CoWare, Inc., Frontier Design, Inc. and others. All Rights reserved.
The contents of this file are subject to the restrictions and limitations
set forth in the SystemC Open Source License Version 2.0 (the "License");
You may not use this file except in compliance with such restrictions and
limitations. You may obtain instructions on how to receive a copy of the
License at http://www.systemc.org/.  Software distributed by Contributors
under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
ANY KIND, either express or implied. See the License for the specific
language governing rights and limitations under the License."

******************************************************************************/

/****************************************************************
    sc_pid.h --  process id class for software threads

    Authors
	: Harish Sarin, CoWare Inc. (harish@coware.com)
	: Cesar Quiroz, CoWare Inc. (cesar@coware.com)
    : Vijay Kumar,  CoWare Inc. (vijay@coware.com)

    MODIFICATION LOG 
    Modifier Name & Affiliation:
    Description of Modification:


****************************************************************/

#ifndef SC_PID_H
#define SC_PID_H

#include "sc_object.h"
#include "sc_list.h"
#include "sc_process.h"

enum sc_thread_status{suspended=0,runnable,killed};

class sc_signal_base;
class sc_process_b;
class sc_pid {
 public:
	sc_module *instance;
	//CTOR
	sc_pid(sc_aproc_process_handle);
	// helper function
	static void make_dynamic_thread(sc_aproc_process_handle h,sc_signal_base *sig=0);
	static sc_pid* get_process_pid(sc_aproc_process_handle h);  // helper function
	bool is_dynamic();

	sc_aproc_process_handle m_aproc_handle; 
	static sc_plist<sc_pid *> m_runnable_threads;
	static sc_plist<sc_pid *> m_suspended_threads;
	static sc_plist<sc_pid *> m_killed_threads;
	static sc_plist<sc_pid *> m_invoke_once_threads;
	sc_thread_status current_state;
	sc_aproc_process_handle get_process_handle() { return m_aproc_handle; }
	sc_pid * get_parent();
	void set_thread_status(sc_thread_status s) { current_state = s; }
	sc_thread_status sc_get_thread_status() { return current_state; }
	
 private:
	friend class sc_module;
	friend class sc_simcontext;
	bool Stop();
	bool Start();
	bool Kill();
	bool waiting();
 private:
	bool Self();
	bool m_dynamic;
};

class sc_software_signal_mixin {
public:
	static void kill_aprocs();
};

//////////////////////////////////////////////////////////////////
template<class T> class sc_software_signal : public sc_signal<T> ,public sc_software_signal_mixin {
 public:
	sc_software_signal(const char *nm=0)
		: sc_signal<T>(nm) {
		update_func = sc_software_signal<T>::update_prop_none;
	}

	virtual void remove_all_sensitive_aprocs() {
		int i;
		sc_aproc_process_handle aproc;
		for(i=sensitive_aprocs.size() ; i>0 ; i--) {
			aproc=sensitive_aprocs.fetch(0);
			remove_sensitive_aproc(aproc);
		}
	}

	void toggle() { write(!read()); }
	
	void remove_sensitive_aproc( sc_aproc_process_handle aproc ) const
	{
		int j;
	    for (j = sensitive_aprocs.size() - 1; j >= 0; --j) {
        if (sensitive_aprocs.fetch(j) == aproc)
            break;
	    }
	    if(j>=0)
			sc_signal_base::remove_sensitive_aproc(aproc);
	}
	
	static void update_prop_aproc(sc_signal_base* me) {
	  sc_signal<T>::update_prop_aproc(me);
	  kill_aprocs();
	} 

	static void update_prop_none(sc_signal_base* me) {
	  sc_signal<T>::update_prop_none(me);
	  kill_aprocs();
	}
	
	sc_signal_base::UPDATE_FUNC* update_funcs_array() const {
		static sc_signal_base::UPDATE_FUNC funcs[] = {
			&sc_software_signal<T>::update_prop_none,
			&sc_software_signal<T>::update_prop_aproc,
			&sc_software_signal<T>::update_prop_aproc,
			&sc_software_signal<T>::update_prop_aproc,
		};
		return funcs;
	}
};


#endif
