// $Id$
// Agent Manager

// Copyright (C) 1995 Technische Universitaet Braunschweig, Germany.
// Written by Andreas Zeller <zeller@gnu.org>.
// 
// This file is part of DDD.
// 
// DDD is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
// 
// DDD 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 General Public License for more details.
// 
// You should have received a copy of the GNU General Public
// License along with DDD -- see the file COPYING.
// If not, see <http://www.gnu.org/licenses/>.
// 
// DDD is the data display debugger.
// For details, see the DDD World-Wide-Web page, 
// `http://www.gnu.org/software/ddd/',
// or send a mail to the DDD developers <ddd@gnu.org>.

char AgentM_rcsid[] = 
    "$Id$";

#include "AgentM.h"
#include "Agent.h"
#include "SignalB.h"
#include "config.h"

extern "C" {
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
}

DEFINE_TYPE_INFO_0(AgentManager)

#if 0
#include "SignalC.h"

// Make sure to call all destructors, even when a signal comes
static SignalCleanup hasta_la_vista_you_filthy_agents;
#endif


// Add an agent
void AgentManager::operator += (Agent *key)
{
    for (Agent *c = first; c != 0; c = c->next)
	if (c == key)
	    return;

    SignalBlocker sb(SIGCHLD);

    key->next = first;
    first     = key;
}

// Remove an agent
void AgentManager::operator -= (Agent *key)
{
    Agent *prev = 0;
    for (Agent *c = first; c != 0; c = c->next)
    {
	if (c == key)
	{
	    SignalBlocker sb(SIGCHLD);

	    if (prev == 0)
		first = c->next;
	    else
		prev->next = c->next;
	}
	else
	{
	    prev = c;
	}
    }
}


// Search an agent
Agent *AgentManager::search(int pid)
{
    for (Agent *c = first; c != 0; c = c->next)
	if (pid == c->pid())
	    return c;

    return 0;
}

// Commit all pending changes
void AgentManager::commit()
{
    for (Agent *c = first; c != 0; c = c->next)
	c->commit();
}

// Agent Manager Destructor: called at the end of the show
AgentManager::~AgentManager()
{
    // Terminate using low-level functions
    for (Agent *c = first; c != 0; c = c->next)
	c->terminate(true);
}

// Process status change
bool AgentManager::childStatusChange()
{
    bool gotit = false;

    for (Agent *c = first; c != 0; c = c->next)
    {
	pid_t pid = c->pid();
	int status;

	if (pid > 0 && waitpid(pid, &status, WNOHANG) == pid)
	{
	    c->callHandlers(_Died, (void *)status);
	    gotit = true;
	}
    }

    return gotit;
}
