<commit_before>/*
 * Copyright 2015 BrewPi/Elco Jacobs.
 *
 * This file is part of BrewPi.
 *
 * BrewPi 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.
 *
 * BrewPi 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 BrewPi.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "Control.h"
#include "Platform.h"

#include <vector>
#include "Pid.h"
#include "defaultDevices.h"
#include "ActuatorInterfaces.h"
#include "ActuatorPwm.h"
#include "ActuatorTimeLimited.h"
#include "TempSensor.h"
#include "ActuatorSetPoint.h"
#include "ActuatorMutexDriver.h"
#include "ActuatorMutexGroup.h"
#include "json_writer.h"
#include "VisitorCast.h"

Control::Control()
{
    // set up static devices for backwards compatibility with tempControl
    beer1Sensor = new TempSensor(defaultTempSensor());
    beer1Sensor->setName("beer1");
    beer2Sensor = new TempSensor(defaultTempSensor());
    beer2Sensor->setName("beer2");
    fridgeSensor = new TempSensor(defaultTempSensor());
    fridgeSensor->setName("fridge");

    mutex = new ActuatorMutexGroup();

    heater1Mutex = new ActuatorMutexDriver(defaultActuator(), mutex);
    heater1 = new ActuatorPwm(heater1Mutex, 4); // period 4s

    heater2Mutex = new ActuatorMutexDriver(defaultActuator(), mutex);
    heater2 = new ActuatorPwm(heater2Mutex, 4); // period 4s

    coolerTimeLimited = new ActuatorTimeLimited(defaultActuator(), 120, 180); // 2 min minOn time, 3 min minOff
    coolerMutex = new ActuatorMutexDriver(coolerTimeLimited, mutex);
    cooler = new ActuatorPwm(coolerMutex, 1200); // period 20 min

    beer1Set = new SetPointSimple();
    beer2Set = new SetPointSimple();
    fridgeSet = new SetPointSimple();

    fridgeSetPointActuator = new ActuatorSetPoint(fridgeSet, fridgeSensor, beer1Set);
    fridgeSetPointActuator->setMin(-10.0);
    fridgeSetPointActuator->setMax(10.0);

    heaterInputSensor = new TempSensorFallback(fridgeSensor, beer1Sensor);
    heater1Pid = new Pid(PtrLookup(heaterInputSensor), PtrLookup(heater1), PtrLookup(fridgeSet));
    heater1Pid->setName("heater1");

    coolerInputSensor = new TempSensorFallback(fridgeSensor, beer1Sensor);
    coolerPid = new Pid(PtrLookup(coolerInputSensor), PtrLookup(cooler), PtrLookup(fridgeSet));
    coolerPid->setActuatorIsNegative(true);
    coolerPid->setName("cooler");

    heater2Pid = new Pid(PtrLookup(beer2Sensor), PtrLookup(heater2), PtrLookup(beer2Set));
    heater2Pid->setName("heater2");

    beerToFridgePid = new Pid(PtrLookup(beer1Sensor), PtrLookup(fridgeSetPointActuator), PtrLookup(beer1Set));
    beerToFridgePid->setName("beer2fridge");

    beer1Set->setName("beer1set");
    beer2Set->setName("beer2set");
    fridgeSet->setName("fridgeset");

    objects.push_back(heater1Pid);
    objects.push_back(heater2Pid);
    objects.push_back(coolerPid);
    objects.push_back(beerToFridgePid);

    objects.push_back(fridgeSensor);
    objects.push_back(beer1Sensor);
    objects.push_back(beer2Sensor);
    objects.push_back(coolerInputSensor);
    objects.push_back(heaterInputSensor);

    objects.push_back(cooler);
    objects.push_back(heater1);
    objects.push_back(heater2);

    objects.push_back(beer1Set);
    objects.push_back(beer2Set);
    objects.push_back(fridgeSet);

    objects.push_back(mutex);

    mutex->setDeadTime(1800000); // 30 minutes
}

Control::~Control(){
#if defined(ARDUINO) || defined(SPARK)
    // global control object is static and never destroyed.
    // omit proper destructor to save space.
#else
    delete heater1Mutex;
    delete heater1;

    delete heater2Mutex;
    delete heater2;

    delete coolerTimeLimited;
    delete coolerMutex;
    delete cooler;

    delete fridgeSetPointActuator;

    delete beer1Set;
    delete beer2Set;
    delete fridgeSet;

    delete mutex;

    delete heater1Pid;
    delete heater2Pid;
    delete coolerPid;
    delete beerToFridgePid;

    objects.clear();
#endif
}

// This update function should be called every second
void Control::update(){
    for ( auto &obj : objects ) {
        obj->update();
    }
}

void Control::fastUpdate(){
    for ( auto &obj : objects ) {
    	obj->fastUpdate();
    }
}

void Control::serialize(JSON::Adapter& adapter){
    JSON::Class root(adapter, "Control");
    std::vector<Pid *> pids;
    for ( auto &obj : objects ) {
        Pid * pid = asInterface<Pid>(obj);
        if(pid){
            pids.push_back(pid);
        }
    }
    JSON_T(adapter, pids);
}

Control control;
<commit_msg>small size optimization<commit_after>/*
 * Copyright 2015 BrewPi/Elco Jacobs.
 *
 * This file is part of BrewPi.
 *
 * BrewPi 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.
 *
 * BrewPi 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 BrewPi.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "Control.h"
#include "Platform.h"

#include <vector>
#include "Pid.h"
#include "defaultDevices.h"
#include "ActuatorInterfaces.h"
#include "ActuatorPwm.h"
#include "ActuatorTimeLimited.h"
#include "TempSensor.h"
#include "ActuatorSetPoint.h"
#include "ActuatorMutexDriver.h"
#include "ActuatorMutexGroup.h"
#include "json_writer.h"
#include "VisitorCast.h"

Control::Control()
{
    // set up static devices for backwards compatibility with tempControl
    beer1Sensor = new TempSensor(defaultTempSensor());
    beer1Sensor->setName("beer1");
    beer2Sensor = new TempSensor(defaultTempSensor());
    beer2Sensor->setName("beer2");
    fridgeSensor = new TempSensor(defaultTempSensor());
    fridgeSensor->setName("fridge");

    mutex = new ActuatorMutexGroup();

    heater1Mutex = new ActuatorMutexDriver(defaultActuator(), mutex);
    heater1 = new ActuatorPwm(heater1Mutex, 4); // period 4s

    heater2Mutex = new ActuatorMutexDriver(defaultActuator(), mutex);
    heater2 = new ActuatorPwm(heater2Mutex, 4); // period 4s

    coolerTimeLimited = new ActuatorTimeLimited(defaultActuator(), 120, 180); // 2 min minOn time, 3 min minOff
    coolerMutex = new ActuatorMutexDriver(coolerTimeLimited, mutex);
    cooler = new ActuatorPwm(coolerMutex, 1200); // period 20 min

    beer1Set = new SetPointSimple();
    beer2Set = new SetPointSimple();
    fridgeSet = new SetPointSimple();

    fridgeSetPointActuator = new ActuatorSetPoint(fridgeSet, fridgeSensor, beer1Set);
    fridgeSetPointActuator->setMin(-10.0);
    fridgeSetPointActuator->setMax(10.0);

    heaterInputSensor = new TempSensorFallback(fridgeSensor, beer1Sensor);
    heater1Pid = new Pid(PtrLookup(heaterInputSensor), PtrLookup(heater1), PtrLookup(fridgeSet));
    heater1Pid->setName("heater1");

    coolerInputSensor = new TempSensorFallback(fridgeSensor, beer1Sensor);
    coolerPid = new Pid(PtrLookup(coolerInputSensor), PtrLookup(cooler), PtrLookup(fridgeSet));
    coolerPid->setActuatorIsNegative(true);
    coolerPid->setName("cooler");

    heater2Pid = new Pid(PtrLookup(beer2Sensor), PtrLookup(heater2), PtrLookup(beer2Set));
    heater2Pid->setName("heater2");

    beerToFridgePid = new Pid(PtrLookup(beer1Sensor), PtrLookup(fridgeSetPointActuator), PtrLookup(beer1Set));
    beerToFridgePid->setName("beer2fridge");

    beer1Set->setName("beer1set");
    beer2Set->setName("beer2set");
    fridgeSet->setName("fridgeset");

    objects.push_back(heater1Pid);
    objects.push_back(heater2Pid);
    objects.push_back(coolerPid);
    objects.push_back(beerToFridgePid);

    objects.push_back(fridgeSensor);
    objects.push_back(beer1Sensor);
    objects.push_back(beer2Sensor);
    objects.push_back(coolerInputSensor);
    objects.push_back(heaterInputSensor);

    objects.push_back(cooler);
    objects.push_back(heater1);
    objects.push_back(heater2);

    objects.push_back(beer1Set);
    objects.push_back(beer2Set);
    objects.push_back(fridgeSet);

    objects.push_back(mutex);

    mutex->setDeadTime(1800000); // 30 minutes
}

Control::~Control(){
#if defined(ARDUINO) || defined(SPARK)
    // global control object is static and never destroyed.
    // omit proper destructor to save space.
#else
    delete heater1Mutex;
    delete heater1;

    delete heater2Mutex;
    delete heater2;

    delete coolerTimeLimited;
    delete coolerMutex;
    delete cooler;

    delete fridgeSetPointActuator;

    delete beer1Set;
    delete beer2Set;
    delete fridgeSet;

    delete mutex;

    delete heater1Pid;
    delete heater2Pid;
    delete coolerPid;
    delete beerToFridgePid;

    objects.clear();
#endif
}

// This update function should be called every second
void Control::update(){
    for ( auto &obj : objects ) {
        obj->update();
    }
}

void Control::fastUpdate(){
    for ( auto &obj : objects ) {
    	obj->fastUpdate();
    }
}

void Control::serialize(JSON::Adapter& adapter){
    JSON::Class root(adapter, "Control");
    std::vector<Interface *> pids;
    VisitorCast<Pid> vcp;
    // filter out only PIDs
    for ( auto &obj : objects ) {
        obj->accept(vcp);
        if(vcp.getCastResult() != nullptr){
            pids.push_back(obj);
        }
    }
    JSON_T(adapter, pids);
}

Control control;
<|endoftext|>


<commit_before>/****************************************************************
Purpose:
	The checkpoint (a.out) file transferred from the submitting machine
	should be a valid ULTRIX executable file, and should have been linked
	with the Condor remote execution library.  Here we check the
	magic numbers to determine if we have a valid executable file, and
	also look for a well known symbol from the Condor library (MAIN)
	to ensure proper linking.

Note : The file has been modified for the Solaris platform by :
	   Dhaval N. Shah
	   University of Wisconsin, Computer Sciences Department.

Portability:
	This code depends upon the executable format for ULTRIX.4.2 systems,
	and is not portable to other systems.
******************************************************************/

#define _ALL_SOURCE

#include "condor_common.h"
#include "condor_debug.h"
#include "condor_constants.h"
#include "condor_jobqueue.h"
#include <sys/file.h>
#include <sys/exec.h>
#include <sys/exechdr.h>
#include "proto.h"
#include <nlist.h>

static char *_FileName_ = __FILE__;     /* Used by EXCEPT (see except.h)     */

#if defined(X86)
#define SOLARIS_MAGIC 043114
#else
#define SOLARIS_MAGIC 046106
#endif

extern "C" {
#if defined(Solaris)
	int nlist( const char *FileName, struct nlist *nl);
#else
	int nlist( char *FileName, struct nlist *nl);
#endif
}

int magic_check( char *a_out )
{
	int		exec_fd;
	struct exec	header;
	int		nbytes;

	if( (exec_fd=open(a_out,O_RDONLY,0)) < 0 ) {
		dprintf( D_ALWAYS, "open(%s,O_RDONLY,0)", a_out );
		return -1;
	}
	dprintf( D_ALWAYS, "Opened file \"%s\", fd = %d\n", a_out, exec_fd );

	errno = 0;
	nbytes = read( exec_fd, (char *)&header, sizeof(header) );
	if( nbytes != sizeof(header) ) {
		dprintf(D_ALWAYS,
			"Error on read(%d,0x%x,%d), nbytes = %d, errno = %d\n",
			exec_fd, (char *)&header, sizeof(header), nbytes, errno
		);
		close( exec_fd );
		return -1;
	}

	close( exec_fd );

	if( header.a_magic != SOLARIS_MAGIC ) {
		dprintf( D_ALWAYS, "\"%s\": BAD MAGIC NUMBER\n", a_out );
		dprintf( D_ALWAYS, "0x%x != 0x%x\n", header.a_magic, SOLARIS_MAGIC );
		dprintf( D_ALWAYS, "0%o != 0%o\n", header.a_magic, SOLARIS_MAGIC );
		dprintf( D_ALWAYS, "%d != %d\n", header.a_magic, SOLARIS_MAGIC );
		return -1;
	}
	if( header.a_machtype != 69 ) {
		dprintf( D_ALWAYS,
			"\"%s\": NOT COMPILED FOR SPARC ARCHITECTURE\n", a_out
		);
		dprintf( D_ALWAYS, "%d != %d\n", header.a_machtype, 69 );
		return -1;
	}
#if (!defined Solaris)
	if( header.a_dynamic ) {
		dprintf( D_ALWAYS, "\"%s\": LINKED FOR DYNAMIC LOADING\n", a_out );
		return -1;
	}
#endif
	return 0;
}

/*
Check to see that the checkpoint file is linked with the Condor
library by looking for the symbol "MAIN".
*/
int symbol_main_check( char *name )
{
	int	status;
	struct nlist nl[2];

	/* Unlike on some other architectures, we want to look for
	   MAIN and _condor_prestart on Solaris, not _MAIN and
	   __condor_prestart.  -Jim B. */

	nl[0].n_name = "MAIN";
	nl[1].n_name = "_condor_prestart";
	nl[2].n_name = "";

		/* If nlist fails just return TRUE - executable may be stripped. */
	status = nlist( name, nl );
	if( status < 0 ) {
		dprintf(D_ALWAYS, "Error: nlist(\"%s\",0x%x) returns %d, errno = %d\n",
													name, nl, status, errno);
		return(0);
	}

	if( nl[0].n_type == 0 ) {
		dprintf( D_ALWAYS, "No symbol \"MAIN\" in executable(%s)\n", name );
		return(-1);
	}

	if( nl[1].n_type == 0 ) {
		dprintf( D_ALWAYS,
				"No symbol \"_condor_prestart\" in executable(%s)\n", name );
		return(-1);
	}

	dprintf( D_ALWAYS, "Symbol MAIN check - OK\n" );
	return 0;
}

int
calc_hdr_blocks()
{
	return (sizeof(struct exec) + 1023) / 1024;
}

int
calc_text_blocks( char *a_out )
{
	int		exec_fd;
	struct exec	header;

	if( (exec_fd=open(a_out,O_RDONLY,0)) < 0 ) {
		dprintf( D_ALWAYS, "open(%s,O_RDONLY,0)", a_out );
		return -1;
	}

	if( read(exec_fd,(char *)&header,sizeof(header)) != sizeof(header) ) {
		dprintf(D_ALWAYS,
			"read(%d,0x%x,%d)", exec_fd, (char *)&header, sizeof(header)
		);
		close( exec_fd );
		return -1;
	}

	close( exec_fd );

	return header.a_text / 1024;
}
<commit_msg>   Since a_machtype is not defined on X86 Solaris, I put in #ifdef's around the header.a_machtype test.<commit_after>/****************************************************************
Purpose:
	The checkpoint (a.out) file transferred from the submitting machine
	should be a valid ULTRIX executable file, and should have been linked
	with the Condor remote execution library.  Here we check the
	magic numbers to determine if we have a valid executable file, and
	also look for a well known symbol from the Condor library (MAIN)
	to ensure proper linking.

Note : The file has been modified for the Solaris platform by :
	   Dhaval N. Shah
	   University of Wisconsin, Computer Sciences Department.

Portability:
	This code depends upon the executable format for ULTRIX.4.2 systems,
	and is not portable to other systems.
******************************************************************/

#define _ALL_SOURCE

#include "condor_common.h"
#include "condor_debug.h"
#include "condor_constants.h"
#include "condor_jobqueue.h"
#include <sys/file.h>
#include <sys/exec.h>
#include <sys/exechdr.h>
#include "proto.h"
#include <nlist.h>

static char *_FileName_ = __FILE__;     /* Used by EXCEPT (see except.h)     */

#if defined(X86)
#define SOLARIS_MAGIC 043114
#else
#define SOLARIS_MAGIC 046106
#endif

extern "C" {
#if defined(Solaris)
	int nlist( const char *FileName, struct nlist *nl);
#else
	int nlist( char *FileName, struct nlist *nl);
#endif
}

int magic_check( char *a_out )
{
	int		exec_fd;
	struct exec	header;
	int		nbytes;

	if( (exec_fd=open(a_out,O_RDONLY,0)) < 0 ) {
		dprintf( D_ALWAYS, "open(%s,O_RDONLY,0)", a_out );
		return -1;
	}
	dprintf( D_ALWAYS, "Opened file \"%s\", fd = %d\n", a_out, exec_fd );

	errno = 0;
	nbytes = read( exec_fd, (char *)&header, sizeof(header) );
	if( nbytes != sizeof(header) ) {
		dprintf(D_ALWAYS,
			"Error on read(%d,0x%x,%d), nbytes = %d, errno = %d\n",
			exec_fd, (char *)&header, sizeof(header), nbytes, errno
		);
		close( exec_fd );
		return -1;
	}

	close( exec_fd );

	if( header.a_magic != SOLARIS_MAGIC ) {
		dprintf( D_ALWAYS, "\"%s\": BAD MAGIC NUMBER\n", a_out );
		dprintf( D_ALWAYS, "0x%x != 0x%x\n", header.a_magic, SOLARIS_MAGIC );
		dprintf( D_ALWAYS, "0%o != 0%o\n", header.a_magic, SOLARIS_MAGIC );
		dprintf( D_ALWAYS, "%d != %d\n", header.a_magic, SOLARIS_MAGIC );
		return -1;
	}

#if !defined(X86)
	if( header.a_machtype != 69 ) {
		dprintf( D_ALWAYS,
			"\"%s\": NOT COMPILED FOR SPARC ARCHITECTURE\n", a_out
		);
		dprintf( D_ALWAYS, "%d != %d\n", header.a_machtype, 69 );
		return -1;
	}
#endif

#if (!defined Solaris)
	if( header.a_dynamic ) {
		dprintf( D_ALWAYS, "\"%s\": LINKED FOR DYNAMIC LOADING\n", a_out );
		return -1;
	}
#endif
	return 0;
}

/*
Check to see that the checkpoint file is linked with the Condor
library by looking for the symbol "MAIN".
*/
int symbol_main_check( char *name )
{
	int	status;
	struct nlist nl[2];

	/* Unlike on some other architectures, we want to look for
	   MAIN and _condor_prestart on Solaris, not _MAIN and
	   __condor_prestart.  -Jim B. */

	nl[0].n_name = "MAIN";
	nl[1].n_name = "_condor_prestart";
	nl[2].n_name = "";

		/* If nlist fails just return TRUE - executable may be stripped. */
	status = nlist( name, nl );
	if( status < 0 ) {
		dprintf(D_ALWAYS, "Error: nlist(\"%s\",0x%x) returns %d, errno = %d\n",
													name, nl, status, errno);
		return(0);
	}

	if( nl[0].n_type == 0 ) {
		dprintf( D_ALWAYS, "No symbol \"MAIN\" in executable(%s)\n", name );
		return(-1);
	}

	if( nl[1].n_type == 0 ) {
		dprintf( D_ALWAYS,
				"No symbol \"_condor_prestart\" in executable(%s)\n", name );
		return(-1);
	}

	dprintf( D_ALWAYS, "Symbol MAIN check - OK\n" );
	return 0;
}

int
calc_hdr_blocks()
{
	return (sizeof(struct exec) + 1023) / 1024;
}

int
calc_text_blocks( char *a_out )
{
	int		exec_fd;
	struct exec	header;

	if( (exec_fd=open(a_out,O_RDONLY,0)) < 0 ) {
		dprintf( D_ALWAYS, "open(%s,O_RDONLY,0)", a_out );
		return -1;
	}

	if( read(exec_fd,(char *)&header,sizeof(header)) != sizeof(header) ) {
		dprintf(D_ALWAYS,
			"read(%d,0x%x,%d)", exec_fd, (char *)&header, sizeof(header)
		);
		close( exec_fd );
		return -1;
	}

	close( exec_fd );

	return header.a_text / 1024;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <qplatformdefs.h>

#include "qfilesystemwatcher.h"
#include "qfilesystemwatcher_kqueue_p.h"
#include "private/qcore_unix_p.h"

#include <qdebug.h>
#include <qfile.h>
#include <qsocketnotifier.h>
#include <qvarlengtharray.h>

#include <sys/types.h>
#include <sys/event.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>

QT_BEGIN_NAMESPACE

// #define KEVENT_DEBUG
#ifdef KEVENT_DEBUG
#  define DEBUG qDebug
#else
#  define DEBUG if(false)qDebug
#endif

QKqueueFileSystemWatcherEngine *QKqueueFileSystemWatcherEngine::create()
{
    int kqfd = kqueue();
    if (kqfd == -1)
        return 0;
    return new QKqueueFileSystemWatcherEngine(kqfd);
}

QKqueueFileSystemWatcherEngine::QKqueueFileSystemWatcherEngine(int kqfd)
    : kqfd(kqfd)
{
    fcntl(kqfd, F_SETFD, FD_CLOEXEC);

    if (pipe(kqpipe) == -1) {
        perror("QKqueueFileSystemWatcherEngine: cannot create pipe");
        kqpipe[0] = kqpipe[1] = -1;
        return;
    }
    fcntl(kqpipe[0], F_SETFD, FD_CLOEXEC);
    fcntl(kqpipe[1], F_SETFD, FD_CLOEXEC);

    struct kevent kev;
    EV_SET(&kev,
           kqpipe[0],
           EVFILT_READ,
           EV_ADD | EV_ENABLE,
           0,
           0,
           0);
    if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) {
        perror("QKqueueFileSystemWatcherEngine: cannot watch pipe, kevent returned");
        return;
    }
}

QKqueueFileSystemWatcherEngine::~QKqueueFileSystemWatcherEngine()
{
    stop();
    wait();

    close(kqfd);
    close(kqpipe[0]);
    close(kqpipe[1]);

    foreach (int id, pathToID.values())
        ::close(id < 0 ? -id : id);
}

QStringList QKqueueFileSystemWatcherEngine::addPaths(const QStringList &paths,
                                                     QStringList *files,
                                                     QStringList *directories)
{
    QMutexLocker locker(&mutex);

    QStringList p = paths;
    QMutableListIterator<QString> it(p);
    while (it.hasNext()) {
        QString path = it.next();
        int fd;
#if defined(O_EVTONLY)
        fd = qt_safe_open(QFile::encodeName(path), O_EVTONLY);
#else
        fd = qt_safe_open(QFile::encodeName(path), O_RDONLY);
#endif
        if (fd == -1) {
            perror("QKqueueFileSystemWatcherEngine::addPaths: open");
            continue;
        }

        QT_STATBUF st;
        if (QT_FSTAT(fd, &st) == -1) {
            perror("QKqueueFileSystemWatcherEngine::addPaths: fstat");
            ::close(fd);
            continue;
        }
        int id = (S_ISDIR(st.st_mode)) ? -fd : fd;
        if (id < 0) {
            if (directories->contains(path)) {
                ::close(fd);
                continue;
            }
        } else {
            if (files->contains(path)) {
                ::close(fd);
                continue;
            }
        }

        struct kevent kev;
        EV_SET(&kev,
               fd,
               EVFILT_VNODE,
               EV_ADD | EV_ENABLE | EV_ONESHOT,
               NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE,
               0,
               0);
        if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) {
            perror("QKqueueFileSystemWatcherEngine::addPaths: kevent");
            ::close(fd);
            continue;
        }

        it.remove();
        if (id < 0) {
            DEBUG() << "QKqueueFileSystemWatcherEngine: added directory path" << path;
            directories->append(path);
        } else {
            DEBUG() << "QKqueueFileSystemWatcherEngine: added file path" << path;
            files->append(path);
        }

        pathToID.insert(path, id);
        idToPath.insert(id, path);
    }

    if (!isRunning())
        start();
    else
        write(kqpipe[1], "@", 1);

    return p;
}

QStringList QKqueueFileSystemWatcherEngine::removePaths(const QStringList &paths,
                                                        QStringList *files,
                                                        QStringList *directories)
{
    QMutexLocker locker(&mutex);

    QStringList p = paths;
    QMutableListIterator<QString> it(p);
    while (it.hasNext()) {
        QString path = it.next();
        int id = pathToID.take(path);
        QString x = idToPath.take(id);
        if (x.isEmpty() || x != path)
            continue;

        int fd = id < 0 ? -id : id;
        struct kevent kev;
        EV_SET(&kev,
               fd,
               EVFILT_VNODE,
               EV_DELETE,
               NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE,
               0,
               0);
        if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) {
            perror("QKqueueFileSystemWatcherEngine::removeWatch: kevent");
        }
        ::close(fd);

        it.remove();
        if (id < 0)
            directories->removeAll(path);
        else
            files->removeAll(path);
    }

    if (pathToID.isEmpty()) {
        stop();
        locker.unlock();
        wait();
        locker.relock();
    } else {
        write(kqpipe[1], "@", 1);
    }

    return p;
}

void QKqueueFileSystemWatcherEngine::stop()
{
    write(kqpipe[1], "q", 1);
}

void QKqueueFileSystemWatcherEngine::run()
{
    static const struct timespec ZeroTimeout = { 0, 0 };

    forever {
        struct kevent kev;
        DEBUG() << "QKqueueFileSystemWatcherEngine: waiting for kevents...";
        int r = kevent(kqfd, 0, 0, &kev, 1, 0);
        if (r < 0) {
            perror("QKqueueFileSystemWatcherEngine: error during kevent wait");
            return;
        }

        QMutexLocker locker(&mutex);
        do {
            int fd = kev.ident;

            DEBUG() << "QKqueueFileSystemWatcherEngine: processing kevent" << kev.ident << kev.filter;
            if (fd == kqpipe[0]) {
                char c;
                if (read(kqpipe[0], &c, 1) != 1) {
                    perror("QKqueueFileSystemWatcherEngine: error reading from pipe");
                    return;
                }
                switch (c) {
                case 'q':
                    DEBUG() << "QKqueueFileSystemWatcherEngine: thread received 'q', exiting...";
                    return;
                case '@':
                    DEBUG() << "QKqueueFileSystemWatcherEngine: thread received '@', continuing...";
                    break;
                default:
                    DEBUG() << "QKqueueFileSystemWatcherEngine: thread received unknow message" << c;
                    break;
                }
            } else {
                int id = fd;
                QString path = idToPath.value(id);
                if (path.isEmpty()) {
                    // perhaps a directory?
                    id = -id;
                    path = idToPath.value(id);
                    if (path.isEmpty()) {
                        DEBUG() << "QKqueueFileSystemWatcherEngine: received a kevent for a file we're not watching";
                        continue;
                    }
                }
                if (kev.filter != EVFILT_VNODE) {
                    DEBUG() << "QKqueueFileSystemWatcherEngine: received a kevent with the wrong filter";
                    continue;
                }

                if ((kev.fflags & (NOTE_DELETE | NOTE_REVOKE | NOTE_RENAME)) != 0) {
                    DEBUG() << path << "removed, removing watch also";

                    pathToID.remove(path);
                    idToPath.remove(id);
                    ::close(fd);

                    if (id < 0)
                        emit directoryChanged(path, true);
                    else
                        emit fileChanged(path, true);
                } else {
                    DEBUG() << path << "changed, re-enabling watch";

                    if (id < 0)
                        emit directoryChanged(path, false);
                    else
                        emit fileChanged(path, false);

                    // renable the watch
                    EV_SET(&kev,
                           fd,
                           EVFILT_VNODE,
                           EV_ADD | EV_ENABLE | EV_ONESHOT,
                           NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE,
                           0,
                           0);
                    if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) {
                        perror("QKqueueFileSystemWatcherEngine::processKqueueEvents: kevent EV_ADD");
                    }
                }
            }

            // are there any more?
            r = kevent(kqfd, 0, 0, &kev, 1, &ZeroTimeout);
        } while (r > 0);
    }
}

QT_END_NAMESPACE
<commit_msg>Fix a deadlock in kqueue implementation of QFileSystemWatcher<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <qplatformdefs.h>

#include "qfilesystemwatcher.h"
#include "qfilesystemwatcher_kqueue_p.h"
#include "private/qcore_unix_p.h"

#include <qdebug.h>
#include <qfile.h>
#include <qsocketnotifier.h>
#include <qvarlengtharray.h>

#include <sys/types.h>
#include <sys/event.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>

QT_BEGIN_NAMESPACE

// #define KEVENT_DEBUG
#ifdef KEVENT_DEBUG
#  define DEBUG qDebug
#else
#  define DEBUG if(false)qDebug
#endif

QKqueueFileSystemWatcherEngine *QKqueueFileSystemWatcherEngine::create()
{
    int kqfd = kqueue();
    if (kqfd == -1)
        return 0;
    return new QKqueueFileSystemWatcherEngine(kqfd);
}

QKqueueFileSystemWatcherEngine::QKqueueFileSystemWatcherEngine(int kqfd)
    : kqfd(kqfd)
{
    fcntl(kqfd, F_SETFD, FD_CLOEXEC);

    if (pipe(kqpipe) == -1) {
        perror("QKqueueFileSystemWatcherEngine: cannot create pipe");
        kqpipe[0] = kqpipe[1] = -1;
        return;
    }
    fcntl(kqpipe[0], F_SETFD, FD_CLOEXEC);
    fcntl(kqpipe[1], F_SETFD, FD_CLOEXEC);

    struct kevent kev;
    EV_SET(&kev,
           kqpipe[0],
           EVFILT_READ,
           EV_ADD | EV_ENABLE,
           0,
           0,
           0);
    if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) {
        perror("QKqueueFileSystemWatcherEngine: cannot watch pipe, kevent returned");
        return;
    }
}

QKqueueFileSystemWatcherEngine::~QKqueueFileSystemWatcherEngine()
{
    stop();
    wait();

    close(kqfd);
    close(kqpipe[0]);
    close(kqpipe[1]);

    foreach (int id, pathToID.values())
        ::close(id < 0 ? -id : id);
}

QStringList QKqueueFileSystemWatcherEngine::addPaths(const QStringList &paths,
                                                     QStringList *files,
                                                     QStringList *directories)
{
    QMutexLocker locker(&mutex);

    QStringList p = paths;
    QMutableListIterator<QString> it(p);
    while (it.hasNext()) {
        QString path = it.next();
        int fd;
#if defined(O_EVTONLY)
        fd = qt_safe_open(QFile::encodeName(path), O_EVTONLY);
#else
        fd = qt_safe_open(QFile::encodeName(path), O_RDONLY);
#endif
        if (fd == -1) {
            perror("QKqueueFileSystemWatcherEngine::addPaths: open");
            continue;
        }

        QT_STATBUF st;
        if (QT_FSTAT(fd, &st) == -1) {
            perror("QKqueueFileSystemWatcherEngine::addPaths: fstat");
            ::close(fd);
            continue;
        }
        int id = (S_ISDIR(st.st_mode)) ? -fd : fd;
        if (id < 0) {
            if (directories->contains(path)) {
                ::close(fd);
                continue;
            }
        } else {
            if (files->contains(path)) {
                ::close(fd);
                continue;
            }
        }

        struct kevent kev;
        EV_SET(&kev,
               fd,
               EVFILT_VNODE,
               EV_ADD | EV_ENABLE | EV_ONESHOT,
               NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE,
               0,
               0);
        if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) {
            perror("QKqueueFileSystemWatcherEngine::addPaths: kevent");
            ::close(fd);
            continue;
        }

        it.remove();
        if (id < 0) {
            DEBUG() << "QKqueueFileSystemWatcherEngine: added directory path" << path;
            directories->append(path);
        } else {
            DEBUG() << "QKqueueFileSystemWatcherEngine: added file path" << path;
            files->append(path);
        }

        pathToID.insert(path, id);
        idToPath.insert(id, path);
    }

    if (!isRunning())
        start();
    else
        write(kqpipe[1], "@", 1);

    return p;
}

QStringList QKqueueFileSystemWatcherEngine::removePaths(const QStringList &paths,
                                                        QStringList *files,
                                                        QStringList *directories)
{
    QMutexLocker locker(&mutex);

    QStringList p = paths;
    QMutableListIterator<QString> it(p);
    while (it.hasNext()) {
        QString path = it.next();
        int id = pathToID.take(path);
        QString x = idToPath.take(id);
        if (x.isEmpty() || x != path)
            continue;

        int fd = id < 0 ? -id : id;
        struct kevent kev;
        EV_SET(&kev,
               fd,
               EVFILT_VNODE,
               EV_DELETE,
               NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE,
               0,
               0);
        if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) {
            perror("QKqueueFileSystemWatcherEngine::removeWatch: kevent");
        }
        ::close(fd);

        it.remove();
        if (id < 0)
            directories->removeAll(path);
        else
            files->removeAll(path);
    }

    if (pathToID.isEmpty()) {
        stop();
        locker.unlock();
        wait();
        locker.relock();
    } else {
        write(kqpipe[1], "@", 1);
    }

    return p;
}

void QKqueueFileSystemWatcherEngine::stop()
{
    write(kqpipe[1], "q", 1);
}

void QKqueueFileSystemWatcherEngine::run()
{
    static const struct timespec ZeroTimeout = { 0, 0 };

    forever {
        struct kevent kev;
        DEBUG() << "QKqueueFileSystemWatcherEngine: waiting for kevents...";
        int r = kevent(kqfd, 0, 0, &kev, 1, 0);
        if (r < 0) {
            perror("QKqueueFileSystemWatcherEngine: error during kevent wait");
            return;
        }

        QMutexLocker locker(&mutex);
        do {
            int fd = kev.ident;

            DEBUG() << "QKqueueFileSystemWatcherEngine: processing kevent" << kev.ident << kev.filter;
            if (fd == kqpipe[0]) {
                // read all pending data from the pipe
                QByteArray ba;
                ba.resize(kev.data);
                if (read(kqpipe[0], ba.data(), ba.size()) != ba.size()) {
                    perror("QKqueueFileSystemWatcherEngine: error reading from pipe");
                    return;
                }
                // read the command from the buffer (but break and return on 'q')
                char cmd = 0;
                for (int i = 0; i < ba.size(); ++i) {
                    cmd = ba.constData()[i];
                    if (cmd == 'q')
                        break;
                }
                // handle the command
                switch (cmd) {
                case 'q':
                    DEBUG() << "QKqueueFileSystemWatcherEngine: thread received 'q', exiting...";
                    return;
                case '@':
                    DEBUG() << "QKqueueFileSystemWatcherEngine: thread received '@', continuing...";
                    break;
                default:
                    DEBUG() << "QKqueueFileSystemWatcherEngine: thread received unknow message" << cmd;
                    break;
                }
            } else {
                int id = fd;
                QString path = idToPath.value(id);
                if (path.isEmpty()) {
                    // perhaps a directory?
                    id = -id;
                    path = idToPath.value(id);
                    if (path.isEmpty()) {
                        DEBUG() << "QKqueueFileSystemWatcherEngine: received a kevent for a file we're not watching";
                        continue;
                    }
                }
                if (kev.filter != EVFILT_VNODE) {
                    DEBUG() << "QKqueueFileSystemWatcherEngine: received a kevent with the wrong filter";
                    continue;
                }

                if ((kev.fflags & (NOTE_DELETE | NOTE_REVOKE | NOTE_RENAME)) != 0) {
                    DEBUG() << path << "removed, removing watch also";

                    pathToID.remove(path);
                    idToPath.remove(id);
                    ::close(fd);

                    if (id < 0)
                        emit directoryChanged(path, true);
                    else
                        emit fileChanged(path, true);
                } else {
                    DEBUG() << path << "changed, re-enabling watch";

                    if (id < 0)
                        emit directoryChanged(path, false);
                    else
                        emit fileChanged(path, false);

                    // renable the watch
                    EV_SET(&kev,
                           fd,
                           EVFILT_VNODE,
                           EV_ADD | EV_ENABLE | EV_ONESHOT,
                           NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE,
                           0,
                           0);
                    if (kevent(kqfd, &kev, 1, 0, 0, 0) == -1) {
                        perror("QKqueueFileSystemWatcherEngine::processKqueueEvents: kevent EV_ADD");
                    }
                }
            }

            // are there any more?
            r = kevent(kqfd, 0, 0, &kev, 1, &ZeroTimeout);
        } while (r > 0);
    }
}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qmlobjectscriptclass_p.h"
#include <private/qmlengine_p.h>
#include <private/qguard_p.h>
#include <private/qmlcontext_p.h>
#include <private/qmldeclarativedata_p.h>
#include <private/qmltypenamescriptclass_p.h>
#include <QtDeclarative/qmlbinding.h>
#include <QtCore/qtimer.h>

QT_BEGIN_NAMESPACE

struct ObjectData : public QScriptDeclarativeClass::Object {
    ObjectData(QObject *o) : object(o) {}
    QGuard<QObject> object;
};

/*
    The QmlObjectScriptClass handles property access for QObjects
    via QtScript. It is also used to provide a more useful API in
    QtScript for QML.
 */
QmlObjectScriptClass::QmlObjectScriptClass(QmlEngine *bindEngine)
: QScriptDeclarativeClass(QmlEnginePrivate::getScriptEngine(bindEngine)), lastData(0),
  engine(bindEngine)
{
    engine = bindEngine;
    QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(bindEngine);

    m_destroy = scriptEngine->newFunction(destroy);
    m_destroyId = createPersistentIdentifier(QLatin1String("destroy"));
    m_toString = scriptEngine->newFunction(tostring);
    m_toStringId = createPersistentIdentifier(QLatin1String("toString"));
}

QmlObjectScriptClass::~QmlObjectScriptClass()
{
}

QScriptValue QmlObjectScriptClass::newQObject(QObject *object)
{
    QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine);

    if (!object)
        return newObject(scriptEngine, this, new ObjectData(object));

    QmlDeclarativeData *ddata = QmlDeclarativeData::get(object, true);

    if (!ddata->scriptValue.isValid()) {
        ddata->scriptValue = newObject(scriptEngine, this, new ObjectData(object));
        return ddata->scriptValue;
    } else if (ddata->scriptValue.engine() == QmlEnginePrivate::getScriptEngine(engine)) {
        return ddata->scriptValue;
    } else {
        return newObject(scriptEngine, this, new ObjectData(object));
    }
}

QObject *QmlObjectScriptClass::toQObject(const QScriptValue &value) const
{
    return value.toQObject();
}

QScriptClass::QueryFlags
QmlObjectScriptClass::queryProperty(Object *object, const Identifier &name,
                                    QScriptClass::QueryFlags flags)
{
    return queryProperty(toQObject(object), name, flags, 0);
}

QScriptClass::QueryFlags
QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name,
                                    QScriptClass::QueryFlags flags, QmlContext *evalContext)
{
    Q_UNUSED(flags);
    lastData = 0;
    lastTNData = 0;

    if (name == m_destroyId.identifier ||
        name == m_toStringId.identifier)
        return QScriptClass::HandlesReadAccess;

    if (!obj)
        return 0;

    QmlEnginePrivate *enginePrivate = QmlEnginePrivate::get(engine);
    QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine);

    QmlPropertyCache *cache = 0;
    QmlDeclarativeData *ddata = QmlDeclarativeData::get(obj);
    if (ddata)
        cache = ddata->propertyCache;
    if (!cache) {
        cache = enginePrivate->cache(obj);
        if (ddata) { cache->addref(); ddata->propertyCache = cache; }
    }

    if (cache) {
        lastData = cache->property(name);
    } else {
        local = QmlPropertyCache::create(obj->metaObject(), toString(name));
        if (local.isValid())
            lastData = &local;
    }

    if (lastData) {
        QScriptClass::QueryFlags rv = QScriptClass::HandlesReadAccess;
        if (lastData->flags & QmlPropertyCache::Data::IsWritable)
            rv |= QScriptClass::HandlesWriteAccess;
        return rv;
    }

    if (!evalContext && context) {
        // Global object, QScriptContext activation object, QmlContext object
        QScriptValue scopeNode = scopeChainValue(context, 3);
        Q_ASSERT(scopeNode.isValid());
        Q_ASSERT(scriptClass(scopeNode) == enginePrivate->contextClass);

        evalContext = enginePrivate->contextClass->contextFromValue(scopeNode);
    }

    if (evalContext) {
        QmlContextPrivate *cp = QmlContextPrivate::get(evalContext);

        if (cp->imports) {
            QmlTypeNameCache::Data *data = cp->imports->data(name);
            if (data) {
                lastTNData = data;
                return QScriptClass::HandlesReadAccess;
            }
        }
    }

    return 0;
}

QScriptValue QmlObjectScriptClass::property(Object *object, const Identifier &name)
{
    return property(toQObject(object), name);
}

QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name)
{
    if (name == m_destroyId.identifier)
        return m_destroy;
    else if (name == m_toStringId.identifier)
        return m_toString;

    Q_ASSERT(obj);

    QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine);
    QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine);

    if (lastTNData) {

        if (lastTNData->type)
            return enginePriv->typeNameClass->newObject(obj, lastTNData->type);
        else
            return enginePriv->typeNameClass->newObject(obj, lastTNData->typeNamespace);

    } else if (lastData->flags & QmlPropertyCache::Data::IsFunction) {
        // ### Optimize
        QScriptValue sobj = scriptEngine->newQObject(obj);
        return sobj.property(toString(name));
    } else {
        if (!(lastData->flags & QmlPropertyCache::Data::IsConstant)) {
            enginePriv->capturedProperties <<
                QmlEnginePrivate::CapturedProperty(obj, lastData->coreIndex, lastData->notifyIndex);
        }

        if ((uint)lastData->propType < QVariant::UserType) {
            QmlValueType *valueType = enginePriv->valueTypes[lastData->propType];
            if (valueType)
                return enginePriv->valueTypeClass->newObject(obj, lastData->coreIndex, valueType);
        }

        QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj);

        if (lastData->flags & QmlPropertyCache::Data::IsQObjectDerived) {
            QObject *rv = *(QObject **)var.constData();
            return newQObject(rv);
        } else {
            return enginePriv->scriptValueFromVariant(var);
        }

    }
}

void QmlObjectScriptClass::setProperty(Object *object,
                                       const Identifier &name,
                                       const QScriptValue &value)
{
    return setProperty(toQObject(object), name, value);
}

void QmlObjectScriptClass::setProperty(QObject *obj,
                                       const Identifier &name,
                                       const QScriptValue &value)
{
    Q_UNUSED(name);

    Q_ASSERT(obj);
    Q_ASSERT(lastData);

    QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine);

    // ### Can well known types be optimized?
    QVariant v = QmlScriptClass::toVariant(engine, value);
    delete QmlMetaPropertyPrivate::setBinding(obj, *lastData, 0);
    QmlMetaPropertyPrivate::write(obj, *lastData, v, enginePriv->currentExpression->context());
}

QObject *QmlObjectScriptClass::toQObject(Object *object, bool *ok)
{
    if (ok) *ok = true;

    ObjectData *data = (ObjectData*)object;
    return data->object.data();
}

QScriptValue QmlObjectScriptClass::tostring(QScriptContext *context, QScriptEngine *)
{
    QObject* obj = context->thisObject().toQObject();

    QString ret;
    if(obj){
        QString objectName = obj->objectName();

        ret += QLatin1String(obj->metaObject()->className());
        ret += QLatin1String("(0x");
        ret += QString::number((quintptr)obj,16);

        if (!objectName.isEmpty()) {
            ret += QLatin1String(", \"");
            ret += objectName;
            ret += QLatin1String("\"");
        }

        ret += QLatin1String(")");
    }else{
        ret += QLatin1String("null");
    }
    return QScriptValue(ret);
}

QScriptValue QmlObjectScriptClass::destroy(QScriptContext *context, QScriptEngine *engine)
{
    QObject* obj = context->thisObject().toQObject();
    if(obj){
        int delay = 0;
        if(context->argumentCount() > 0)
            delay = context->argument(0).toInt32();
        if (delay > 0)
            QTimer::singleShot(delay, obj, SLOT(deleteLater()));
        else
            obj->deleteLater();
    }
    return engine->nullValue();
}

QT_END_NAMESPACE

<commit_msg>Update to use new QScriptDeclarativeClass API<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qmlobjectscriptclass_p.h"
#include <private/qmlengine_p.h>
#include <private/qguard_p.h>
#include <private/qmlcontext_p.h>
#include <private/qmldeclarativedata_p.h>
#include <private/qmltypenamescriptclass_p.h>
#include <QtDeclarative/qmlbinding.h>
#include <QtCore/qtimer.h>

QT_BEGIN_NAMESPACE

struct ObjectData : public QScriptDeclarativeClass::Object {
    ObjectData(QObject *o) : object(o) {}
    QGuard<QObject> object;
};

/*
    The QmlObjectScriptClass handles property access for QObjects
    via QtScript. It is also used to provide a more useful API in
    QtScript for QML.
 */
QmlObjectScriptClass::QmlObjectScriptClass(QmlEngine *bindEngine)
: QScriptDeclarativeClass(QmlEnginePrivate::getScriptEngine(bindEngine)), lastData(0),
  engine(bindEngine)
{
    engine = bindEngine;
    QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(bindEngine);

    m_destroy = scriptEngine->newFunction(destroy);
    m_destroyId = createPersistentIdentifier(QLatin1String("destroy"));
    m_toString = scriptEngine->newFunction(tostring);
    m_toStringId = createPersistentIdentifier(QLatin1String("toString"));
}

QmlObjectScriptClass::~QmlObjectScriptClass()
{
}

QScriptValue QmlObjectScriptClass::newQObject(QObject *object)
{
    QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine);

    if (!object)
        return newObject(scriptEngine, this, new ObjectData(object));

    QmlDeclarativeData *ddata = QmlDeclarativeData::get(object, true);

    if (!ddata->scriptValue.isValid()) {
        ddata->scriptValue = newObject(scriptEngine, this, new ObjectData(object));
        return ddata->scriptValue;
    } else if (ddata->scriptValue.engine() == QmlEnginePrivate::getScriptEngine(engine)) {
        return ddata->scriptValue;
    } else {
        return newObject(scriptEngine, this, new ObjectData(object));
    }
}

QObject *QmlObjectScriptClass::toQObject(const QScriptValue &value) const
{
    return value.toQObject();
}

QScriptClass::QueryFlags
QmlObjectScriptClass::queryProperty(Object *object, const Identifier &name,
                                    QScriptClass::QueryFlags flags)
{
    return queryProperty(toQObject(object), name, flags, 0);
}

QScriptClass::QueryFlags
QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name,
                                    QScriptClass::QueryFlags flags, QmlContext *evalContext)
{
    Q_UNUSED(flags);
    lastData = 0;
    lastTNData = 0;

    if (name == m_destroyId.identifier ||
        name == m_toStringId.identifier)
        return QScriptClass::HandlesReadAccess;

    if (!obj)
        return 0;

    QmlEnginePrivate *enginePrivate = QmlEnginePrivate::get(engine);
    QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine);

    QmlPropertyCache *cache = 0;
    QmlDeclarativeData *ddata = QmlDeclarativeData::get(obj);
    if (ddata)
        cache = ddata->propertyCache;
    if (!cache) {
        cache = enginePrivate->cache(obj);
        if (ddata) { cache->addref(); ddata->propertyCache = cache; }
    }

    if (cache) {
        lastData = cache->property(name);
    } else {
        local = QmlPropertyCache::create(obj->metaObject(), toString(name));
        if (local.isValid())
            lastData = &local;
    }

    if (lastData) {
        QScriptClass::QueryFlags rv = QScriptClass::HandlesReadAccess;
        if (lastData->flags & QmlPropertyCache::Data::IsWritable)
            rv |= QScriptClass::HandlesWriteAccess;
        return rv;
    }

    if (!evalContext && context()) {
        // Global object, QScriptContext activation object, QmlContext object
        QScriptValue scopeNode = scopeChainValue(context(), -3);
        Q_ASSERT(scopeNode.isValid());
        Q_ASSERT(scriptClass(scopeNode) == enginePrivate->contextClass);

        evalContext = enginePrivate->contextClass->contextFromValue(scopeNode);
    }

    if (evalContext) {
        QmlContextPrivate *cp = QmlContextPrivate::get(evalContext);

        if (cp->imports) {
            QmlTypeNameCache::Data *data = cp->imports->data(name);
            if (data) {
                lastTNData = data;
                return QScriptClass::HandlesReadAccess;
            }
        }
    }

    return 0;
}

QScriptValue QmlObjectScriptClass::property(Object *object, const Identifier &name)
{
    return property(toQObject(object), name);
}

QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name)
{
    if (name == m_destroyId.identifier)
        return m_destroy;
    else if (name == m_toStringId.identifier)
        return m_toString;

    Q_ASSERT(obj);

    QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine);
    QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine);

    if (lastTNData) {

        if (lastTNData->type)
            return enginePriv->typeNameClass->newObject(obj, lastTNData->type);
        else
            return enginePriv->typeNameClass->newObject(obj, lastTNData->typeNamespace);

    } else if (lastData->flags & QmlPropertyCache::Data::IsFunction) {
        // ### Optimize
        QScriptValue sobj = scriptEngine->newQObject(obj);
        return sobj.property(toString(name));
    } else {
        if (!(lastData->flags & QmlPropertyCache::Data::IsConstant)) {
            enginePriv->capturedProperties <<
                QmlEnginePrivate::CapturedProperty(obj, lastData->coreIndex, lastData->notifyIndex);
        }

        if ((uint)lastData->propType < QVariant::UserType) {
            QmlValueType *valueType = enginePriv->valueTypes[lastData->propType];
            if (valueType)
                return enginePriv->valueTypeClass->newObject(obj, lastData->coreIndex, valueType);
        }

        QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj);

        if (lastData->flags & QmlPropertyCache::Data::IsQObjectDerived) {
            QObject *rv = *(QObject **)var.constData();
            return newQObject(rv);
        } else {
            return enginePriv->scriptValueFromVariant(var);
        }

    }
}

void QmlObjectScriptClass::setProperty(Object *object,
                                       const Identifier &name,
                                       const QScriptValue &value)
{
    return setProperty(toQObject(object), name, value);
}

void QmlObjectScriptClass::setProperty(QObject *obj,
                                       const Identifier &name,
                                       const QScriptValue &value)
{
    Q_UNUSED(name);

    Q_ASSERT(obj);
    Q_ASSERT(lastData);

    QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine);

    // ### Can well known types be optimized?
    QVariant v = QmlScriptClass::toVariant(engine, value);
    delete QmlMetaPropertyPrivate::setBinding(obj, *lastData, 0);
    QmlMetaPropertyPrivate::write(obj, *lastData, v, enginePriv->currentExpression->context());
}

QObject *QmlObjectScriptClass::toQObject(Object *object, bool *ok)
{
    if (ok) *ok = true;

    ObjectData *data = (ObjectData*)object;
    return data->object.data();
}

QScriptValue QmlObjectScriptClass::tostring(QScriptContext *context, QScriptEngine *)
{
    QObject* obj = context->thisObject().toQObject();

    QString ret;
    if(obj){
        QString objectName = obj->objectName();

        ret += QLatin1String(obj->metaObject()->className());
        ret += QLatin1String("(0x");
        ret += QString::number((quintptr)obj,16);

        if (!objectName.isEmpty()) {
            ret += QLatin1String(", \"");
            ret += objectName;
            ret += QLatin1String("\"");
        }

        ret += QLatin1String(")");
    }else{
        ret += QLatin1String("null");
    }
    return QScriptValue(ret);
}

QScriptValue QmlObjectScriptClass::destroy(QScriptContext *context, QScriptEngine *engine)
{
    QObject* obj = context->thisObject().toQObject();
    if(obj){
        int delay = 0;
        if(context->argumentCount() > 0)
            delay = context->argument(0).toInt32();
        if (delay > 0)
            QTimer::singleShot(delay, obj, SLOT(deleteLater()));
        else
            obj->deleteLater();
    }
    return engine->nullValue();
}

QT_END_NAMESPACE

<|endoftext|>


<commit_before>#include "engine/fibers.h"

namespace Lumix
{

namespace Fiber
{

bool init(Engine& engine)
{
	ASSERT(false);
}

void shutdown()
{
	ASSERT(false);
}

Handle createFromThread(void* parameter)
{
	ASSERT(false);
	return nullptr;
}

Handle create(int stack_size, FiberProc proc, void* parameter)
{
	ASSERT(false);
	return nullptr;
}

void destroy(Handle fiber)
{
	ASSERT(false);
}

void switchTo(Handle fiber)
{
	ASSERT(false);
}

void* getParameter()
{
	ASSERT(false);
	return nullptr;
}

} // namespace Fibers

} // namespace Lumix<commit_msg>missin include on linux<commit_after>#include "engine/fibers.h"
#include "engine/lumix.h"

namespace Lumix
{

namespace Fiber
{

bool init(Engine& engine)
{
	ASSERT(false);
}

void shutdown()
{
	ASSERT(false);
}

Handle createFromThread(void* parameter)
{
	ASSERT(false);
	return nullptr;
}

Handle create(int stack_size, FiberProc proc, void* parameter)
{
	ASSERT(false);
	return nullptr;
}

void destroy(Handle fiber)
{
	ASSERT(false);
}

void switchTo(Handle fiber)
{
	ASSERT(false);
}

void* getParameter()
{
	ASSERT(false);
	return nullptr;
}

} // namespace Fibers

} // namespace Lumix<|endoftext|>


<commit_before>#include "AssembledSolver.h"

#include <sofa/component/linearsolver/EigenSparseMatrix.h>
#include <sofa/component/linearsolver/EigenVector.h>
#include <sofa/core/ObjectFactory.h>
#include <sofa/simulation/common/MechanicalOperations.h>
#include <sofa/simulation/common/VectorOperations.h>

#include "AssemblyVisitor.h"

#include "utils/minres.h"
#include "utils/scoped.h"

namespace sofa {
namespace component {
namespace odesolver {

SOFA_DECL_CLASS(AssembledSolver);
int AssembledSolverClass = core::RegisterObject("Example compliance solver using assembly").add< AssembledSolver >();

using namespace sofa::defaulttype;
using namespace sofa::helper;
using namespace core::behavior;

AssembledSolver::AssembledSolver()
	: use_velocity(initData(&use_velocity,
	                        false,
	                        "use_velocity",
	                        "solve velocity dynamics (otherwise acceleration)")),
	  warm_start(initData(&warm_start,
	                      false,
	                      "warm_start",
	                      "warm start iterative solvers: avoids biasing solution towards zero."))
{

}

void AssembledSolver::send(simulation::Visitor& vis) {
	scoped::timer step("visitor execution");

	this->getContext()->executeVisitor( &vis );
}

void AssembledSolver::integrate(const core::MechanicalParams* params) {
	scoped::timer step("position integration");
	SReal dt = params->dt();

	// integrate positions
	sofa::simulation::common::VectorOperations vop( params, this->getContext() );
	MultiVecCoord pos(&vop, core::VecCoordId::position() );
	MultiVecDeriv vel(&vop, core::VecDerivId::velocity() );

	typedef core::behavior::BaseMechanicalState::VMultiOp VMultiOp;
	VMultiOp multi;

	multi.resize(1);

	multi[0].first = pos.id();
	multi[0].second.push_back( std::make_pair(pos.id(), 1.0) );
	multi[0].second.push_back( std::make_pair(vel.id(), dt) );

	vop.v_multiop( multi );
}

void AssembledSolver::forces(const core::ExecParams& params) {
	scoped::timer step("forces computation");

	sofa::simulation::common::MechanicalOperations mop( &params, this->getContext() );
	sofa::simulation::common::VectorOperations vop( &params, this->getContext() );

	MultiVecDeriv f  (&vop, core::VecDerivId::force() );

	mop.computeForce(f);
	// mop.projectResponse(f);
}

void AssembledSolver::propagate(const core::MechanicalParams* params) {
	simulation::MechanicalPropagatePositionAndVelocityVisitor bob( params );
	send( bob );
}

core::MechanicalParams AssembledSolver::mparams(const core::ExecParams& params,
                                                double dt) const {
	core::MechanicalParams res( params );

	res.setMFactor( 1.0 );
	res.setDt( dt );

	res.setImplicitVelocity( 1 );
	res.setImplicitPosition( 1 );

	return res;
}

// velocity implicit euler
linearsolver::KKTSolver::vec AssembledSolver::rhs(const system_type& sys) const {

	kkt_type::vec res = kkt_type::vec::Zero( sys.size() );

	kkt_type::vec p = sys.p  +  sys.dt * sys.f;

	res.head( sys.m ) = sys.P * (use_velocity.getValue() ? p : sys.f);

	if( sys.n ) {

		if( use_velocity.getValue() ) {
			// remove velocity part from rhs as it's handled implicitly here
			// (this is due to weird Compliance API, TODO fix this)
			res.tail( sys.n ) =  sys.phi + sys.J * sys.v;
		} else {
			res.tail( sys.n ) =  sys.phi / sys.dt;
		}

	}

	return res;
}

linearsolver::KKTSolver::vec AssembledSolver::warm(const system_type& sys) const {

	kkt_type::vec res = kkt_type::vec::Zero( sys.size() );

	// warm starting is a bad idea anyways
	if( warm_start.getValue() ) {
		if( use_velocity.getValue() ) res.head( sys.m ) = sys.P * sys.v;
	}

	return res;
}

// AssembledSolver::system_type AssembledSolver::assemble(const simulation::AssemblyVisitor& vis) const {
// 	system_type sys = vis.assemble();

// 	// TODO this should be done during system assembly

// 	// fix compliance
// 	if( sys.n ) {
// 		// std::cerr << "compliance" << std::endl;

// 		system_type::vec h = system_type::vec::Constant(sys.n, sys.dt);
// 		system_type::vec fix; fix.resize(sys.n);

// 		fix.array() = 1 / ( h.array() * (h.array() + sys.damping.array()) );

// 		sys.C = sys.C * fix.asDiagonal();
// 	}

// 	return sys;
// }

AssembledSolver::kkt_type::vec AssembledSolver::velocity(const system_type& sys,
                                                         const kkt_type::vec& x) const {
	if( use_velocity.getValue() ) return sys.P * x.head( sys.m );
	else return sys.P * (sys.v + sys.dt * x.head( sys.m ));
}

AssembledSolver::kkt_type::vec AssembledSolver::lambda(const system_type& sys,
                                                       const kkt_type::vec& x) const {
	if( use_velocity.getValue() ) return x.tail( sys.n ) / sys.dt;
	else return x.tail( sys.n );

}

void AssembledSolver::solve(const core::ExecParams* params,
                            double dt,
                            sofa::core::MultiVecCoordId ,
                            sofa::core::MultiVecDerivId ) {
	assert(kkt && "i need a kkt solver lol");

	// obtain mparams
	core::MechanicalParams mparams = this->mparams(*params, dt);

	// compute forces
	forces( mparams );

	// assembly visitor
	simulation::AssemblyVisitor vis(&mparams);

	// fetch data
	send( vis );

	typedef linearsolver::AssembledSystem system_type;

	sofa::helper::AdvancedTimer::stepBegin( "assembly" );
	system_type sys = vis.assemble();
	sofa::helper::AdvancedTimer::stepEnd( "assembly" );

	// solution vector
	system_type::vec x = warm( sys );

	{
		scoped::timer step("system solve");
		kkt->factor( sys );
		kkt->solve(x, sys, rhs( sys ) );
	}

	// distribute (projected) velocities
	vis.distribute_master( core::VecId::velocity(), velocity(sys, x) );
	if( sys.n ) vis.distribute_compliant( core::VecId::force(), lambda(sys, x) );

	// update positions TODO use xResult/vResult
	integrate( &mparams );
}

void AssembledSolver::init() {

	// let's find a KKTSolver
	kkt = this->getContext()->get<kkt_type>();

	// TODO less dramatic error
	if( !kkt ) throw std::logic_error("AssembledSolver needs a KKTSolver lol");

}

}
}
}
<commit_msg>r9452/sofa : Compliant: fixed uninitialized block array in AssembledSolver<commit_after>#include "AssembledSolver.h"

#include <sofa/component/linearsolver/EigenSparseMatrix.h>
#include <sofa/component/linearsolver/EigenVector.h>
#include <sofa/core/ObjectFactory.h>
#include <sofa/simulation/common/MechanicalOperations.h>
#include <sofa/simulation/common/VectorOperations.h>

#include "AssemblyVisitor.h"

#include "utils/minres.h"
#include "utils/scoped.h"

namespace sofa {
namespace component {
namespace odesolver {

SOFA_DECL_CLASS(AssembledSolver);
int AssembledSolverClass = core::RegisterObject("Example compliance solver using assembly").add< AssembledSolver >();

using namespace sofa::defaulttype;
using namespace sofa::helper;
using namespace core::behavior;

AssembledSolver::AssembledSolver()
	: use_velocity(initData(&use_velocity,
	                        false,
	                        "use_velocity",
	                        "solve velocity dynamics (otherwise acceleration)")),
	  warm_start(initData(&warm_start,
	                      false,
	                      "warm_start",
	                      "warm start iterative solvers: avoids biasing solution towards zero."))
{

}

void AssembledSolver::send(simulation::Visitor& vis) {
	scoped::timer step("visitor execution");

	this->getContext()->executeVisitor( &vis );
}

void AssembledSolver::integrate(const core::MechanicalParams* params) {
	scoped::timer step("position integration");
	SReal dt = params->dt();

	// integrate positions
	sofa::simulation::common::VectorOperations vop( params, this->getContext() );
	MultiVecCoord pos(&vop, core::VecCoordId::position() );
	MultiVecDeriv vel(&vop, core::VecDerivId::velocity() );

	typedef core::behavior::BaseMechanicalState::VMultiOp VMultiOp;
	VMultiOp multi;

	multi.resize(1);

	multi[0].first = pos.id();
	multi[0].second.push_back( std::make_pair(pos.id(), 1.0) );
	multi[0].second.push_back( std::make_pair(vel.id(), dt) );

	vop.v_multiop( multi );
}

void AssembledSolver::forces(const core::ExecParams& params) {
	scoped::timer step("forces computation");

	sofa::simulation::common::MechanicalOperations mop( &params, this->getContext() );
	sofa::simulation::common::VectorOperations vop( &params, this->getContext() );

	MultiVecDeriv f  (&vop, core::VecDerivId::force() );

	mop.computeForce(f);
	// mop.projectResponse(f);
}

void AssembledSolver::propagate(const core::MechanicalParams* params) {
	simulation::MechanicalPropagatePositionAndVelocityVisitor bob( params );
	send( bob );
}

core::MechanicalParams AssembledSolver::mparams(const core::ExecParams& params,
                                                double dt) const {
	core::MechanicalParams res( params );

	res.setMFactor( 1.0 );
	res.setDt( dt );

	res.setImplicitVelocity( 1 );
	res.setImplicitPosition( 1 );

	return res;
}

// velocity implicit euler
linearsolver::KKTSolver::vec AssembledSolver::rhs(const system_type& sys) const {

	kkt_type::vec res = kkt_type::vec::Zero( sys.size() );

	kkt_type::vec p = sys.p  +  sys.dt * sys.f;

	res.head( sys.m ) = sys.P * (use_velocity.getValue() ? p : sys.f);

	if( sys.n ) {

		if( use_velocity.getValue() ) {
			// remove velocity part from rhs as it's handled implicitly here
			// (this is due to weird Compliance API, TODO fix this)
			res.tail( sys.n ) =  sys.phi + sys.J * sys.v;
		} else {
			res.tail( sys.n ) =  sys.phi / sys.dt;
		}

	}

	return res;
}

linearsolver::KKTSolver::vec AssembledSolver::warm(const system_type& sys) const {

	kkt_type::vec res = kkt_type::vec::Zero( sys.size() );

	// warm starting is a bad idea anyways
	if( warm_start.getValue() ) {
		if( use_velocity.getValue() ) res.head( sys.m ) = sys.P * sys.v;
	}

	return res;
}

// AssembledSolver::system_type AssembledSolver::assemble(const simulation::AssemblyVisitor& vis) const {
// 	system_type sys = vis.assemble();

// 	// TODO this should be done during system assembly

// 	// fix compliance
// 	if( sys.n ) {
// 		// std::cerr << "compliance" << std::endl;

// 		system_type::vec h = system_type::vec::Constant(sys.n, sys.dt);
// 		system_type::vec fix; fix.resize(sys.n);

// 		fix.array() = 1 / ( h.array() * (h.array() + sys.damping.array()) );

// 		sys.C = sys.C * fix.asDiagonal();
// 	}

// 	return sys;
// }

AssembledSolver::kkt_type::vec AssembledSolver::velocity(const system_type& sys,
                                                         const kkt_type::vec& x) const {
	if( use_velocity.getValue() ) return sys.P * x.head( sys.m );
	else return sys.P * (sys.v + sys.dt * x.head( sys.m ));
}

AssembledSolver::kkt_type::vec AssembledSolver::lambda(const system_type& sys,
                                                       const kkt_type::vec& x) const {
	if( use_velocity.getValue() ) return x.tail( sys.n ) / sys.dt;
	else return x.tail( sys.n );

}

void AssembledSolver::solve(const core::ExecParams* params,
                            double dt,
                            sofa::core::MultiVecCoordId ,
                            sofa::core::MultiVecDerivId ) {
	assert(kkt && "i need a kkt solver lol");

	// obtain mparams
	core::MechanicalParams mparams = this->mparams(*params, dt);

	// compute forces
	forces( mparams );

	// assembly visitor
	simulation::AssemblyVisitor vis(&mparams);

	// fetch data
	send( vis );

	typedef linearsolver::AssembledSystem system_type;

	sofa::helper::AdvancedTimer::stepBegin( "assembly" );
	system_type sys = vis.assemble();
	sofa::helper::AdvancedTimer::stepEnd( "assembly" );

	// solution vector
	system_type::vec x = warm( sys );

	{
		scoped::timer step("system solve");
		kkt->factor( sys );
		kkt->solve(x, sys, rhs( sys ) );
	}

	// distribute (projected) velocities
	vis.distribute_master( core::VecId::velocity(), velocity(sys, x) );
	if( sys.n ) vis.distribute_compliant( core::VecId::force(), lambda(sys, x) );

	// update positions TODO use xResult/vResult
	integrate( &mparams );
}

void AssembledSolver::init() {

	// let's find a KKTSolver
	kkt = this->getContext()->get<kkt_type>();

	// TODO less dramatic error
	if( !kkt ) throw std::logic_error("AssembledSolver needs a KKTSolver lol");

}

}
}
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include "bytes.hh"
#include "timestamp.hh"
#include "tombstone.hh"
#include "gc_clock.hh"
#include "net/byteorder.hh"
#include <cstdint>
#include <iostream>

template<typename T>
static inline
void set_field(bytes& v, unsigned offset, T val) {
    reinterpret_cast<net::packed<T>*>(v.begin() + offset)->raw = net::hton(val);
}

template<typename T>
static inline
T get_field(const bytes_view& v, unsigned offset) {
    return net::ntoh(*reinterpret_cast<const net::packed<T>*>(v.begin() + offset));
}

class atomic_cell_or_collection;

/*
 * Represents atomic cell layout. Works on serialized form.
 *
 * Layout:
 *
 *  <live>  := <int8_t:flags><int64_t:timestamp>(<int32_t:expiry><int32_t:ttl>)?<value>
 *  <dead>  := <int8_t:    0><int64_t:timestamp><int32_t:deletion_time>
 */
class atomic_cell_type final {
private:
    static constexpr int8_t DEAD_FLAGS = 0;
    static constexpr int8_t LIVE_FLAG = 0x01;
    static constexpr int8_t EXPIRY_FLAG = 0x02; // When present, expiry field is present. Set only for live cells
    static constexpr unsigned flags_size = 1;
    static constexpr unsigned timestamp_offset = flags_size;
    static constexpr unsigned timestamp_size = 8;
    static constexpr unsigned expiry_offset = timestamp_offset + timestamp_size;
    static constexpr unsigned expiry_size = 4;
    static constexpr unsigned deletion_time_offset = timestamp_offset + timestamp_size;
    static constexpr unsigned deletion_time_size = 4;
    static constexpr unsigned ttl_offset = expiry_offset + expiry_size;
    static constexpr unsigned ttl_size = 4;
private:
    static bool is_live(const bytes_view& cell) {
        return cell[0] != DEAD_FLAGS;
    }
    static bool is_live_and_has_ttl(const bytes_view& cell) {
        return cell[0] & EXPIRY_FLAG;
    }
    static bool is_dead(const bytes_view& cell) {
        return cell[0] == DEAD_FLAGS;
    }
    // Can be called on live and dead cells
    static api::timestamp_type timestamp(const bytes_view& cell) {
        return get_field<api::timestamp_type>(cell, timestamp_offset);
    }
    // Can be called on live cells only
    static bytes_view value(bytes_view cell) {
        auto expiry_field_size = bool(cell[0] & EXPIRY_FLAG) * (expiry_size + ttl_size);
        auto value_offset = flags_size + timestamp_size + expiry_field_size;
        cell.remove_prefix(value_offset);
        return cell;
    }
    // Can be called only when is_dead() is true.
    static gc_clock::time_point deletion_time(const bytes_view& cell) {
        assert(is_dead(cell));
        return gc_clock::time_point(gc_clock::duration(
            get_field<int32_t>(cell, deletion_time_offset)));
    }
    // Can be called only when is_live_and_has_ttl() is true.
    static gc_clock::time_point expiry(const bytes_view& cell) {
        assert(is_live_and_has_ttl(cell));
        auto expiry = get_field<int32_t>(cell, expiry_offset);
        return gc_clock::time_point(gc_clock::duration(expiry));
    }
    // Can be called only when is_live_and_has_ttl() is true.
    static gc_clock::duration ttl(const bytes_view& cell) {
        assert(is_live_and_has_ttl(cell));
        return gc_clock::duration(get_field<int32_t>(cell, ttl_offset));
    }
    static bytes make_dead(api::timestamp_type timestamp, gc_clock::time_point deletion_time) {
        bytes b(bytes::initialized_later(), flags_size + timestamp_size + deletion_time_size);
        b[0] = DEAD_FLAGS;
        set_field(b, timestamp_offset, timestamp);
        set_field(b, deletion_time_offset, deletion_time.time_since_epoch().count());
        return b;
    }
    static bytes make_live(api::timestamp_type timestamp, bytes_view value) {
        auto value_offset = flags_size + timestamp_size;
        bytes b(bytes::initialized_later(), value_offset + value.size());
        b[0] = LIVE_FLAG;
        set_field(b, timestamp_offset, timestamp);
        std::copy_n(value.begin(), value.size(), b.begin() + value_offset);
        return b;
    }
    static bytes make_live(api::timestamp_type timestamp, bytes_view value, gc_clock::time_point expiry, gc_clock::duration ttl) {
        auto value_offset = flags_size + timestamp_size + expiry_size + ttl_size;
        bytes b(bytes::initialized_later(), value_offset + value.size());
        b[0] = EXPIRY_FLAG | LIVE_FLAG;
        set_field(b, timestamp_offset, timestamp);
        set_field(b, expiry_offset, expiry.time_since_epoch().count());
        set_field(b, ttl_offset, ttl.count());
        std::copy_n(value.begin(), value.size(), b.begin() + value_offset);
        return b;
    }
    template<typename ByteContainer>
    friend class atomic_cell_base;
    friend class atomic_cell;
};

template<typename ByteContainer>
class atomic_cell_base {
protected:
    ByteContainer _data;
protected:
    atomic_cell_base(ByteContainer&& data) : _data(std::forward<ByteContainer>(data)) { }
    atomic_cell_base(const ByteContainer& data) : _data(data) { }
public:
    bool is_live() const {
        return atomic_cell_type::is_live(_data);
    }
    bool is_live(tombstone t) const {
        return is_live() && timestamp() > t.timestamp;
    }
    bool is_live_and_has_ttl() const {
        return atomic_cell_type::is_live_and_has_ttl(_data);
    }
    bool is_dead() const {
        return atomic_cell_type::is_dead(_data);
    }
    // Can be called on live and dead cells
    api::timestamp_type timestamp() const {
        return atomic_cell_type::timestamp(_data);
    }
    // Can be called on live cells only
    bytes_view value() const {
        return atomic_cell_type::value(_data);
    }
    // Can be called only when is_dead()
    gc_clock::time_point deletion_time() const {
        return atomic_cell_type::deletion_time(_data);
    }
    // Can be called only when is_live_and_has_ttl()
    gc_clock::time_point expiry() const {
        return atomic_cell_type::expiry(_data);
    }
    // Can be called only when is_live_and_has_ttl()
    gc_clock::duration ttl() const {
        return atomic_cell_type::ttl(_data);
    }
    bytes_view serialize() const {
        return _data;
    }
};

class atomic_cell_view final : public atomic_cell_base<bytes_view> {
    atomic_cell_view(bytes_view data) : atomic_cell_base(data) {}
public:
    static atomic_cell_view from_bytes(bytes_view data) { return atomic_cell_view(data); }

    friend class atomic_cell;
    friend std::ostream& operator<<(std::ostream& os, const atomic_cell_view& acv);
};

class atomic_cell final : public atomic_cell_base<bytes> {
    atomic_cell(bytes b) : atomic_cell_base(std::move(b)) {}
public:
    atomic_cell(const atomic_cell&) = default;
    atomic_cell(atomic_cell&&) = default;
    atomic_cell& operator=(const atomic_cell&) = default;
    atomic_cell& operator=(atomic_cell&&) = default;
    static atomic_cell from_bytes(bytes b) {
        return atomic_cell(std::move(b));
    }
    atomic_cell(atomic_cell_view other) : atomic_cell_base(bytes { other._data.begin(), other._data.end() }) {}
    operator atomic_cell_view() const {
        return atomic_cell_view(_data);
    }
    static atomic_cell make_dead(api::timestamp_type timestamp, gc_clock::time_point expiry) {
        return atomic_cell_type::make_dead(timestamp, expiry);
    }
    static atomic_cell make_live(api::timestamp_type timestamp, bytes_view value) {
        return atomic_cell_type::make_live(timestamp, value);
    }
    static atomic_cell make_live(api::timestamp_type timestamp, bytes_view value,
        gc_clock::time_point expiry, gc_clock::duration ttl)
    {
        return atomic_cell_type::make_live(timestamp, value, expiry, ttl);
    }
    static atomic_cell make_live(api::timestamp_type timestamp, bytes_view value, ttl_opt ttl) {
        if (!ttl) {
            return atomic_cell_type::make_live(timestamp, value);
        } else {
            return atomic_cell_type::make_live(timestamp, value, gc_clock::now() + *ttl, *ttl);
        }
    }
    friend class atomic_cell_or_collection;
    friend std::ostream& operator<<(std::ostream& os, const atomic_cell& ac);
};

// Represents a mutation of a collection.  Actual format is determined by collection type,
// and is:
//   set:  list of atomic_cell
//   map:  list of pair<atomic_cell, bytes> (for key/value)
//   list: tbd, probably ugly
class collection_mutation {
public:
    struct view {
        bytes_view data;
        bytes_view serialize() const { return data; }
        static view from_bytes(bytes_view v) { return { v }; }
    };
    struct one {
        bytes data;
        one() {}
        one(bytes b) : data(std::move(b)) {}
        one(view v) : data(v.data.begin(), v.data.end()) {}
        operator view() const { return { data }; }
    };
};

namespace db {
template<typename T>
class serializer;
}

// A variant type that can hold either an atomic_cell, or a serialized collection.
// Which type is stored is determinied by the schema.
class atomic_cell_or_collection final {
    bytes _data;

    template<typename T>
    friend class db::serializer;
private:
    atomic_cell_or_collection() = default;
    atomic_cell_or_collection(bytes&& data) : _data(std::move(data)) {}
public:
    atomic_cell_or_collection(atomic_cell ac) : _data(std::move(ac._data)) {}
    static atomic_cell_or_collection from_atomic_cell(atomic_cell data) { return { std::move(data._data) }; }
    atomic_cell_view as_atomic_cell() const { return atomic_cell_view::from_bytes(_data); }
    atomic_cell_or_collection(collection_mutation::one cm) : _data(std::move(cm.data)) {}
    static atomic_cell_or_collection from_collection_mutation(collection_mutation::one data) {
        return std::move(data.data);
    }
    collection_mutation::view as_collection_mutation() const {
        return collection_mutation::view{_data};
    }
    bytes_view serialize() const {
        return _data;
    }
    friend std::ostream& operator<<(std::ostream&, const atomic_cell_or_collection&);
};

class column_definition;

int compare_atomic_cell_for_merge(atomic_cell_view left, atomic_cell_view right);
void merge_column(const column_definition& def,
        atomic_cell_or_collection& old,
        const atomic_cell_or_collection& neww);
<commit_msg>atomic_cell: add checks for expired cells<commit_after>/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include "bytes.hh"
#include "timestamp.hh"
#include "tombstone.hh"
#include "gc_clock.hh"
#include "net/byteorder.hh"
#include <cstdint>
#include <iostream>

template<typename T>
static inline
void set_field(bytes& v, unsigned offset, T val) {
    reinterpret_cast<net::packed<T>*>(v.begin() + offset)->raw = net::hton(val);
}

template<typename T>
static inline
T get_field(const bytes_view& v, unsigned offset) {
    return net::ntoh(*reinterpret_cast<const net::packed<T>*>(v.begin() + offset));
}

class atomic_cell_or_collection;

/*
 * Represents atomic cell layout. Works on serialized form.
 *
 * Layout:
 *
 *  <live>  := <int8_t:flags><int64_t:timestamp>(<int32_t:expiry><int32_t:ttl>)?<value>
 *  <dead>  := <int8_t:    0><int64_t:timestamp><int32_t:deletion_time>
 */
class atomic_cell_type final {
private:
    static constexpr int8_t DEAD_FLAGS = 0;
    static constexpr int8_t LIVE_FLAG = 0x01;
    static constexpr int8_t EXPIRY_FLAG = 0x02; // When present, expiry field is present. Set only for live cells
    static constexpr unsigned flags_size = 1;
    static constexpr unsigned timestamp_offset = flags_size;
    static constexpr unsigned timestamp_size = 8;
    static constexpr unsigned expiry_offset = timestamp_offset + timestamp_size;
    static constexpr unsigned expiry_size = 4;
    static constexpr unsigned deletion_time_offset = timestamp_offset + timestamp_size;
    static constexpr unsigned deletion_time_size = 4;
    static constexpr unsigned ttl_offset = expiry_offset + expiry_size;
    static constexpr unsigned ttl_size = 4;
private:
    static bool is_live(const bytes_view& cell) {
        return cell[0] != DEAD_FLAGS;
    }
    static bool is_live_and_has_ttl(const bytes_view& cell) {
        return cell[0] & EXPIRY_FLAG;
    }
    static bool is_dead(const bytes_view& cell) {
        return cell[0] == DEAD_FLAGS;
    }
    // Can be called on live and dead cells
    static api::timestamp_type timestamp(const bytes_view& cell) {
        return get_field<api::timestamp_type>(cell, timestamp_offset);
    }
    // Can be called on live cells only
    static bytes_view value(bytes_view cell) {
        auto expiry_field_size = bool(cell[0] & EXPIRY_FLAG) * (expiry_size + ttl_size);
        auto value_offset = flags_size + timestamp_size + expiry_field_size;
        cell.remove_prefix(value_offset);
        return cell;
    }
    // Can be called only when is_dead() is true.
    static gc_clock::time_point deletion_time(const bytes_view& cell) {
        assert(is_dead(cell));
        return gc_clock::time_point(gc_clock::duration(
            get_field<int32_t>(cell, deletion_time_offset)));
    }
    // Can be called only when is_live_and_has_ttl() is true.
    static gc_clock::time_point expiry(const bytes_view& cell) {
        assert(is_live_and_has_ttl(cell));
        auto expiry = get_field<int32_t>(cell, expiry_offset);
        return gc_clock::time_point(gc_clock::duration(expiry));
    }
    // Can be called only when is_live_and_has_ttl() is true.
    static gc_clock::duration ttl(const bytes_view& cell) {
        assert(is_live_and_has_ttl(cell));
        return gc_clock::duration(get_field<int32_t>(cell, ttl_offset));
    }
    static bytes make_dead(api::timestamp_type timestamp, gc_clock::time_point deletion_time) {
        bytes b(bytes::initialized_later(), flags_size + timestamp_size + deletion_time_size);
        b[0] = DEAD_FLAGS;
        set_field(b, timestamp_offset, timestamp);
        set_field(b, deletion_time_offset, deletion_time.time_since_epoch().count());
        return b;
    }
    static bytes make_live(api::timestamp_type timestamp, bytes_view value) {
        auto value_offset = flags_size + timestamp_size;
        bytes b(bytes::initialized_later(), value_offset + value.size());
        b[0] = LIVE_FLAG;
        set_field(b, timestamp_offset, timestamp);
        std::copy_n(value.begin(), value.size(), b.begin() + value_offset);
        return b;
    }
    static bytes make_live(api::timestamp_type timestamp, bytes_view value, gc_clock::time_point expiry, gc_clock::duration ttl) {
        auto value_offset = flags_size + timestamp_size + expiry_size + ttl_size;
        bytes b(bytes::initialized_later(), value_offset + value.size());
        b[0] = EXPIRY_FLAG | LIVE_FLAG;
        set_field(b, timestamp_offset, timestamp);
        set_field(b, expiry_offset, expiry.time_since_epoch().count());
        set_field(b, ttl_offset, ttl.count());
        std::copy_n(value.begin(), value.size(), b.begin() + value_offset);
        return b;
    }
    template<typename ByteContainer>
    friend class atomic_cell_base;
    friend class atomic_cell;
};

template<typename ByteContainer>
class atomic_cell_base {
protected:
    ByteContainer _data;
protected:
    atomic_cell_base(ByteContainer&& data) : _data(std::forward<ByteContainer>(data)) { }
    atomic_cell_base(const ByteContainer& data) : _data(data) { }
public:
    bool is_live() const {
        return atomic_cell_type::is_live(_data);
    }
    bool is_live(tombstone t) const {
        return is_live() && timestamp() > t.timestamp;
    }
    bool is_live(tombstone t, gc_clock::time_point now) const {
        return is_live() && timestamp() > t.timestamp && !has_expired(now);
    }
    bool is_live_and_has_ttl() const {
        return atomic_cell_type::is_live_and_has_ttl(_data);
    }
    bool is_dead() const {
        return atomic_cell_type::is_dead(_data);
    }
    bool is_dead(gc_clock::time_point now) const {
        return atomic_cell_type::is_dead(_data) || has_expired(now);
    }
    // Can be called on live and dead cells
    api::timestamp_type timestamp() const {
        return atomic_cell_type::timestamp(_data);
    }
    // Can be called on live cells only
    bytes_view value() const {
        return atomic_cell_type::value(_data);
    }
    // Can be called only when is_dead(gc_clock::time_point)
    gc_clock::time_point deletion_time() const {
        return !is_live() ? atomic_cell_type::deletion_time(_data) : expiry() - ttl();
    }
    // Can be called only when is_live_and_has_ttl()
    gc_clock::time_point expiry() const {
        return atomic_cell_type::expiry(_data);
    }
    // Can be called only when is_live_and_has_ttl()
    gc_clock::duration ttl() const {
        return atomic_cell_type::ttl(_data);
    }
    // Can be called on live and dead cells
    bool has_expired(gc_clock::time_point now) const {
        return is_live_and_has_ttl() && expiry() < now;
    }
    bytes_view serialize() const {
        return _data;
    }
};

class atomic_cell_view final : public atomic_cell_base<bytes_view> {
    atomic_cell_view(bytes_view data) : atomic_cell_base(data) {}
public:
    static atomic_cell_view from_bytes(bytes_view data) { return atomic_cell_view(data); }

    friend class atomic_cell;
    friend std::ostream& operator<<(std::ostream& os, const atomic_cell_view& acv);
};

class atomic_cell final : public atomic_cell_base<bytes> {
    atomic_cell(bytes b) : atomic_cell_base(std::move(b)) {}
public:
    atomic_cell(const atomic_cell&) = default;
    atomic_cell(atomic_cell&&) = default;
    atomic_cell& operator=(const atomic_cell&) = default;
    atomic_cell& operator=(atomic_cell&&) = default;
    static atomic_cell from_bytes(bytes b) {
        return atomic_cell(std::move(b));
    }
    atomic_cell(atomic_cell_view other) : atomic_cell_base(bytes { other._data.begin(), other._data.end() }) {}
    operator atomic_cell_view() const {
        return atomic_cell_view(_data);
    }
    static atomic_cell make_dead(api::timestamp_type timestamp, gc_clock::time_point expiry) {
        return atomic_cell_type::make_dead(timestamp, expiry);
    }
    static atomic_cell make_live(api::timestamp_type timestamp, bytes_view value) {
        return atomic_cell_type::make_live(timestamp, value);
    }
    static atomic_cell make_live(api::timestamp_type timestamp, bytes_view value,
        gc_clock::time_point expiry, gc_clock::duration ttl)
    {
        return atomic_cell_type::make_live(timestamp, value, expiry, ttl);
    }
    static atomic_cell make_live(api::timestamp_type timestamp, bytes_view value, ttl_opt ttl) {
        if (!ttl) {
            return atomic_cell_type::make_live(timestamp, value);
        } else {
            return atomic_cell_type::make_live(timestamp, value, gc_clock::now() + *ttl, *ttl);
        }
    }
    friend class atomic_cell_or_collection;
    friend std::ostream& operator<<(std::ostream& os, const atomic_cell& ac);
};

// Represents a mutation of a collection.  Actual format is determined by collection type,
// and is:
//   set:  list of atomic_cell
//   map:  list of pair<atomic_cell, bytes> (for key/value)
//   list: tbd, probably ugly
class collection_mutation {
public:
    struct view {
        bytes_view data;
        bytes_view serialize() const { return data; }
        static view from_bytes(bytes_view v) { return { v }; }
    };
    struct one {
        bytes data;
        one() {}
        one(bytes b) : data(std::move(b)) {}
        one(view v) : data(v.data.begin(), v.data.end()) {}
        operator view() const { return { data }; }
    };
};

namespace db {
template<typename T>
class serializer;
}

// A variant type that can hold either an atomic_cell, or a serialized collection.
// Which type is stored is determinied by the schema.
class atomic_cell_or_collection final {
    bytes _data;

    template<typename T>
    friend class db::serializer;
private:
    atomic_cell_or_collection() = default;
    atomic_cell_or_collection(bytes&& data) : _data(std::move(data)) {}
public:
    atomic_cell_or_collection(atomic_cell ac) : _data(std::move(ac._data)) {}
    static atomic_cell_or_collection from_atomic_cell(atomic_cell data) { return { std::move(data._data) }; }
    atomic_cell_view as_atomic_cell() const { return atomic_cell_view::from_bytes(_data); }
    atomic_cell_or_collection(collection_mutation::one cm) : _data(std::move(cm.data)) {}
    static atomic_cell_or_collection from_collection_mutation(collection_mutation::one data) {
        return std::move(data.data);
    }
    collection_mutation::view as_collection_mutation() const {
        return collection_mutation::view{_data};
    }
    bytes_view serialize() const {
        return _data;
    }
    friend std::ostream& operator<<(std::ostream&, const atomic_cell_or_collection&);
};

class column_definition;

int compare_atomic_cell_for_merge(atomic_cell_view left, atomic_cell_view right);
void merge_column(const column_definition& def,
        atomic_cell_or_collection& old,
        const atomic_cell_or_collection& neww);
<|endoftext|>


<commit_before>/************************************************************************************
**
* @copyright (c) 2013-2100, ChengDu Duyer Technology Co., LTD. All Right Reserved.
*
*************************************************************************************/
/**
* @file	    g_network_server.cpp
* @version
* @brief
* @author   duye
* @date	    2014-10-07
* @note
*
*  1. 2014-10-07 duye Created this file
*
*/
#include <g_network_server.h>

namespace gcom {

NetworkServer::NetworkServer() {}

NetworkServer::NetworkServer(const IPPortPair& server_addr, const std::string& net_card = "eth0")
    : m_serverAddr(server_addr)
    , m_netCard(net_card) {}

NetworkServer::~NetworkServer() {}

void NetworkServer::addInterface(NetworkServerInterface* interface)
{
    gsys::AutoLock auto_lock(m_interfaceList.mutex());
    InterfaceList::iterator iter = m_interfaceList.begin();
    for (; iter != m_interfaceList.end(); ++iter)
    {
        if (interface == *iter)
        {
            return;
        }
    }

    m_interfaceList.push_back(interface);
}

void NetworkServer::removeInterface(NetworkServerInterface* interface)
{
    gsys::AutoLock auto_lock(m_interfaceList.mutex());
    InterfaceList::iterator iter = m_interfaceList.begin();
    for (; iter != m_interfaceList.end(); ++iter)
    {
        if (*iter == interface)
        {
            m_interfaceList.erase(iter);
            break;
        }
    }
}

const IPPortPair& NetworkServer::getServerAddr() const
{
    return m_serverAddr;
}

const std::string& NetworkServer::getNetCard() const
{
    return m_netCard;
}

const ServerState& NetworkServer::state() const
{
    return m_state;
}

GResult NetworkServer::run()
{
    return routine();
}

GResult NetworkServerMonitor::keepServer(NetworkServer* server)
{
    IS_NULL_R(server);

    switch (server->state)
    {
        case SERVER_INIT:
            return server->start();
            break;
        case SERVER_WORK:
            return G_YES;
            break;
        case SERVER_STOP:
        case SERVER_FAULT:
            return server->restart();
            break;
        default:
            break;
    }

    return G_NO;
}
}
<commit_msg>Update g_network_server.cpp<commit_after>/************************************************************************************
**
* @copyright (c) 2013-2100, ChengDu Duyer Technology Co., LTD. All Right Reserved.
*
*************************************************************************************/
/**
* @file	    g_network_server.cpp
* @version
* @brief
* @author   duye
* @date	    2014-10-07
* @note
*
*  1. 2014-10-07 duye Created this file
*
*/
#include <g_network_server.h>

namespace gcom {

NetworkServer::NetworkServer() {}

NetworkServer::NetworkServer(const IPPortPair& server_addr, const std::string& net_card = "eth0")
    : m_serverAddr(server_addr)
    , m_netCard(net_card) {}

NetworkServer::~NetworkServer() {}

void NetworkServer::addObserver(NetworkServerObserver* observer)
{
    IS_NULL_R(observer);

    gsys::AutoLock auto_lock(m_observerList.mutex());
    ObserverList::iterator iter = m_observerList.begin();
    for (; iter != m_observerList.end(); ++iter)
    {
        if (*iter == observer)
        {
            return;
        }
    }

    m_interfaceList.push_back(observer);
}

void NetworkServer::removeObserver(NetworkServerObserver* observer)
{
    IS_NULL_R(observer);

    gsys::AutoLock auto_lock(m_observerList.mutex());
    ObserverList::iterator iter = m_observerList.begin();
    for (; iter != m_observerList.end(); ++iter)
    {
        if (*iter == observer)
        {
            m_interfaceList.erase(iter);
            break;
        }
    }
}

const IPPortPair& NetworkServer::serverAddr() const
{
    return m_serverAddr;
}

const std::string& NetworkServer::netCard() const
{
    return m_netCard;
}

const ServerState& NetworkServer::state() const
{
    return m_state;
}

ObserverList& NetworkServer::observerList() const
{
    return m_observerList;
}

GResult NetworkServer::run()
{
    return routine();
}

GResult NetworkServerMonitor::keepWork(NetworkServer* server)
{
    IS_NULL_R(server);

    switch (server->state)
    {
        case SERVER_INIT:
            return server->start();
            break;
        case SERVER_WORK:
            return G_YES;
            break;
        case SERVER_STOP:
        case SERVER_FAULT:
            return server->restart();
            break;
        default:
            break;
    }

    return G_NO;
}

}
<|endoftext|>