<commit_before>#include "multiplayer_server_scanner.h"

ServerScanner::ServerScanner(int version_number, int server_port)
: server_port(server_port), version_number(version_number), master_server_scan_thread(&ServerScanner::masterServerScanThread, this)
{
}

ServerScanner::~ServerScanner()
{
    destroy();
    master_server_scan_thread.wait();
}

void ServerScanner::scanMasterServer(string url)
{
    master_server_url = url;
    master_server_scan_thread.launch();
}

void ServerScanner::scanLocalNetwork()
{
    int port_nr = server_port + 1;
    while(socket.bind(port_nr) != sf::UdpSocket::Done)
        port_nr++;

    socket.setBlocking(false);
    broadcast_clock.restart();
}

void ServerScanner::update(float gameDelta)
{
    server_list_mutex.lock();
    for(unsigned int n=0; n<server_list.size(); n++)
    {
        if (server_list[n].timeout_clock.getElapsedTime().asSeconds() > ServerTimeout)
        {
            if (removedServerCallback)
                removedServerCallback(server_list[n].address);
            server_list.erase(server_list.begin() + n);
            n--;
        }
    }
    server_list_mutex.unlock();

    if (socket.getLocalPort() != 0)
    {
        if (broadcast_clock.getElapsedTime().asSeconds() > BroadcastTimeout)
        {
            sf::Packet sendPacket;
            sendPacket << multiplayerVerficationNumber << "ServerQuery" << int32_t(version_number);
            UDPbroadcastPacket(socket, sendPacket, server_port);
            broadcast_clock.restart();
        }

        sf::IpAddress recv_address;
        unsigned short recv_port;
        sf::Packet recv_packet;
        while(socket.receive(recv_packet, recv_address, recv_port) == sf::UdpSocket::Done)
        {
            int32_t verification, version_nr;
            string name;
            recv_packet >> verification >> version_nr >> name;
            if (verification == multiplayerVerficationNumber && (version_nr == version_number || version_nr == 0 || version_number == 0))
            {
                updateServerEntry(recv_address, recv_port, name);
            }
        }
    }
}

void ServerScanner::updateServerEntry(sf::IpAddress address, int port, string name)
{
    sf::Lock lock(server_list_mutex);

    for(unsigned int n=0; n<server_list.size(); n++)
    {
        if (server_list[n].address == address)
        {
            server_list[n].port = port;
            server_list[n].name = name;
            server_list[n].timeout_clock.restart();
            return;
        }
    }

    LOG(INFO) << "ServerScanner::New server: " << address.toString() << " " << port << " " << name;
    ServerInfo si;
    si.address = address;
    si.port = port;
    si.name = name;
    si.timeout_clock.restart();
    server_list.push_back(si);

    if (newServerCallback)
        newServerCallback(address, name);
}

void ServerScanner::addCallbacks(std::function<void(sf::IpAddress, string)> newServerCallback, std::function<void(sf::IpAddress)> removedServerCallback)
{
    this->newServerCallback = newServerCallback;
    this->removedServerCallback = removedServerCallback;
}

std::vector<ServerScanner::ServerInfo> ServerScanner::getServerList()
{
    std::vector<ServerScanner::ServerInfo> ret;
    server_list_mutex.lock();
    ret = server_list;
    server_list_mutex.unlock();
    return ret;
}

void ServerScanner::masterServerScanThread()
{
    if (!master_server_url.startswith("http://"))
    {
        LOG(ERROR) << "Master server URL does not start with \"http://\"";
        return;
    }
    string hostname = master_server_url.substr(7);
    int path_start = hostname.find("/");
    if (path_start < 0)
    {
        LOG(ERROR) << "Master server URL has no uri after hostname";
        return;
    }
    string uri = hostname.substr(path_start + 1);
    hostname = hostname.substr(0, path_start);

    LOG(INFO) << "Reading servers from master server";

    sf::Http http(hostname);
    while(!isDestroyed())
    {
        sf::Http::Request request(uri, sf::Http::Request::Get);
        sf::Http::Response response = http.sendRequest(request, sf::seconds(10.0f));

        if (response.getStatus() != sf::Http::Response::Ok)
        {
            LOG(WARNING) << "Failed to query master server (" << response.getStatus() << ")";
        }
        for(string line : string(response.getBody()).split("\n"))
        {
            std::vector<string> parts = line.split(":", 3);
            if (parts.size() == 4)
            {
                sf::IpAddress address(parts[0]);
                int port = parts[1].toInt();
                int version = parts[2].toInt();
                string name = parts[3];

                if (version == version_number || version == 0 || version_number == 0)
                {
                    updateServerEntry(address, port, name);
                }
            }
        }

        for(int n=0;n<10 && !isDestroyed();n++)
            sf::sleep(sf::seconds(1.0f));
    }
}
<commit_msg>Try to connect to internet servers before listing them, to make sure port forwarding is setup properly at the server.<commit_after>#include "multiplayer_server_scanner.h"

ServerScanner::ServerScanner(int version_number, int server_port)
: server_port(server_port), version_number(version_number), master_server_scan_thread(&ServerScanner::masterServerScanThread, this)
{
}

ServerScanner::~ServerScanner()
{
    destroy();
    master_server_scan_thread.wait();
}

void ServerScanner::scanMasterServer(string url)
{
    master_server_url = url;
    master_server_scan_thread.launch();
}

void ServerScanner::scanLocalNetwork()
{
    int port_nr = server_port + 1;
    while(socket.bind(port_nr) != sf::UdpSocket::Done)
        port_nr++;

    socket.setBlocking(false);
    broadcast_clock.restart();
}

void ServerScanner::update(float gameDelta)
{
    server_list_mutex.lock();
    for(unsigned int n=0; n<server_list.size(); n++)
    {
        if (server_list[n].timeout_clock.getElapsedTime().asSeconds() > ServerTimeout)
        {
            if (removedServerCallback)
                removedServerCallback(server_list[n].address);
            server_list.erase(server_list.begin() + n);
            n--;
        }
    }
    server_list_mutex.unlock();

    if (socket.getLocalPort() != 0)
    {
        if (broadcast_clock.getElapsedTime().asSeconds() > BroadcastTimeout)
        {
            sf::Packet sendPacket;
            sendPacket << multiplayerVerficationNumber << "ServerQuery" << int32_t(version_number);
            UDPbroadcastPacket(socket, sendPacket, server_port);
            broadcast_clock.restart();
        }

        sf::IpAddress recv_address;
        unsigned short recv_port;
        sf::Packet recv_packet;
        while(socket.receive(recv_packet, recv_address, recv_port) == sf::UdpSocket::Done)
        {
            int32_t verification, version_nr;
            string name;
            recv_packet >> verification >> version_nr >> name;
            if (verification == multiplayerVerficationNumber && (version_nr == version_number || version_nr == 0 || version_number == 0))
            {
                updateServerEntry(recv_address, recv_port, name);
            }
        }
    }
}

void ServerScanner::updateServerEntry(sf::IpAddress address, int port, string name)
{
    sf::Lock lock(server_list_mutex);

    for(unsigned int n=0; n<server_list.size(); n++)
    {
        if (server_list[n].address == address)
        {
            server_list[n].port = port;
            server_list[n].name = name;
            server_list[n].timeout_clock.restart();
            return;
        }
    }

    LOG(INFO) << "ServerScanner::New server: " << address.toString() << " " << port << " " << name;
    ServerInfo si;
    si.address = address;
    si.port = port;
    si.name = name;
    si.timeout_clock.restart();
    server_list.push_back(si);

    if (newServerCallback)
        newServerCallback(address, name);
}

void ServerScanner::addCallbacks(std::function<void(sf::IpAddress, string)> newServerCallback, std::function<void(sf::IpAddress)> removedServerCallback)
{
    this->newServerCallback = newServerCallback;
    this->removedServerCallback = removedServerCallback;
}

std::vector<ServerScanner::ServerInfo> ServerScanner::getServerList()
{
    std::vector<ServerScanner::ServerInfo> ret;
    server_list_mutex.lock();
    ret = server_list;
    server_list_mutex.unlock();
    return ret;
}

void ServerScanner::masterServerScanThread()
{
    if (!master_server_url.startswith("http://"))
    {
        LOG(ERROR) << "Master server URL does not start with \"http://\"";
        return;
    }
    string hostname = master_server_url.substr(7);
    int path_start = hostname.find("/");
    if (path_start < 0)
    {
        LOG(ERROR) << "Master server URL has no uri after hostname";
        return;
    }
    string uri = hostname.substr(path_start + 1);
    hostname = hostname.substr(0, path_start);

    LOG(INFO) << "Reading servers from master server";

    sf::Http http(hostname);
    while(!isDestroyed())
    {
        sf::Http::Request request(uri, sf::Http::Request::Get);
        sf::Http::Response response = http.sendRequest(request, sf::seconds(10.0f));

        if (response.getStatus() != sf::Http::Response::Ok)
        {
            LOG(WARNING) << "Failed to query master server (" << response.getStatus() << ")";
        }
        for(string line : string(response.getBody()).split("\n"))
        {
            std::vector<string> parts = line.split(":", 3);
            if (parts.size() == 4)
            {
                sf::IpAddress address(parts[0]);
                int port = parts[1].toInt();
                int version = parts[2].toInt();
                string name = parts[3];

                if (version == version_number || version == 0 || version_number == 0)
                {
                    sf::TcpSocket socket;
                    if (socket.connect(address, port, sf::seconds(1.0)) == sf::Socket::Done)
                    {
                        socket.disconnect();
                        updateServerEntry(address, port, name);
                    }
                }
            }
        }

        for(int n=0;n<10 && !isDestroyed(); n++)
            sf::sleep(sf::seconds(1.0f));
    }
}
<|endoftext|>


<commit_before>/* Copyright (C) 2005-2008, Thorvald Natvig <thorvald@natvig.com>

   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:

   - Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
   - Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.
   - Neither the name of the Mumble Developers nor the names of its
     contributors may be used to endorse or promote products derived from this
     software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "GlobalShortcut_unix.h"
#include "Global.h"
#include <QX11Info>
#include <X11/X.h>
#include <X11/Xlib.h>
#ifdef USE_XEVIE
#include <X11/extensions/Xevie.h>
#endif

#ifdef Q_OS_LINUX
#include <linux/input.h>
#include <fcntl.h>
#endif

GlobalShortcutEngine *GlobalShortcutEngine::platformInit() {
	return new GlobalShortcutX();
}

GlobalShortcutX::GlobalShortcutX() {
	int min, maj;
	bRunning=false;
	bXevie = false;

	display = NULL;

#ifdef Q_OS_LINUX
	QString dir = QLatin1String("/dev/input");
	QFileSystemWatcher *fsw = new QFileSystemWatcher(QStringList(dir), this);
	connect(fsw, SIGNAL(directoryChanged(const QString &)), this, SLOT(directoryChanged(const QString &)));
	directoryChanged(dir);

	if (qmInputDevices.isEmpty()) {
		delete fsw;
		qWarning("GlobalShortcutX: Unable to open any input devices under /dev/input, falling back to XEVIE");
	} else {
		return;
	}
#endif

	display = XOpenDisplay(NULL);

	if (! display) {
		qWarning("GlobalShortcutX: Unable to open dedicated display connection.");
		return;
	}

	maj = 1;
	min = 1;

#ifdef USE_XEVIE
	if (! XevieQueryVersion(display, &maj, &min)) {
		qWarning("GlobalShortcutX: XEVIE extension not found. Enable it in xorg.conf");
	} else {
		qWarning("GlobalShortcutX: XEVIE %d.%d", maj, min);

#ifdef QT_NO_DEBUG
		if (! XevieStart(display)) {
			qWarning("GlobalShortcutX: Another client is already using XEVIE");
		} else {
			XevieSelectInput(display, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
			bXevie = true;
		}
#endif
	}
#else
	qWarning("GlobalShortcutX: Not compiled with XEVIE support.");
#endif
	if (! bXevie) {
		qWarning("GlobalShortcutX: No XEVIE support, falling back to polled input. This wastes a lot of CPU resources, so please enable one of the other methods.");
	}

	bRunning=true;
	start(QThread::TimeCriticalPriority);
}

GlobalShortcutX::~GlobalShortcutX() {
	bRunning = false;
	wait();
}

void GlobalShortcutX::run() {
	fd_set in_fds;
	XEvent evt;
	struct timeval tv;

	if (bXevie) {
#ifdef USE_XEVIE
		while (bRunning) {
			if (bNeedRemap)
				remap();
			FD_ZERO(&in_fds);
			FD_SET(ConnectionNumber(display), &in_fds);
			tv.tv_sec = 0;
			tv.tv_usec = 100000;
			if (select(ConnectionNumber(display)+1, &in_fds, NULL, NULL, &tv)) {
				while (XPending(display)) {
					XNextEvent(display, &evt);
					XevieSendEvent(display, &evt, XEVIE_UNMODIFIED);
					switch (evt.type) {
						case KeyPress:
						case KeyRelease:
						case ButtonPress:
						case ButtonRelease: {
								bool down = (evt.type == KeyPress || evt.type == ButtonPress);
								int evtcode;
								if (evt.type == KeyPress || evt.type == KeyRelease)
									evtcode = evt.xkey.keycode;
								else
									evtcode = 0x118 + evt.xbutton.button;

								handleButton(evtcode, down);
							}
							break;
						default:
							qWarning("GlobalShortcutX: EVT %x", evt.type);
					}
				}
			}
		}
		XevieEnd(display);
#endif
	} else {
		Window root = XDefaultRootWindow(display);
		Window root_ret, child_ret;
		int root_x, root_y;
		int win_x, win_y;
		unsigned int mask[2];
		int idx = 0;
		int next = 0;
		char keys[2][32];

		memset(keys[0], 0, 32);
		memset(keys[1], 0, 32);
		mask[0] = mask[1] = 0;

		while (bRunning) {
			if (bNeedRemap)
				remap();

			msleep(10);

			idx = next;
			next = idx ^ 1;
			if (! XQueryPointer(display, root, &root_ret, &child_ret, &root_x, &root_y, &win_x, &win_y, &mask[next]) ||
			        ! XQueryKeymap(display, keys[next])) {
				qWarning("GlobalShortcutX: Lost connection");
				bRunning = false;
			} else {
				for (int i=0;i<256;++i) {
					int index = i / 8;
					int keymask = 1 << (i % 8);
					bool oldstate = (keys[idx][index] & keymask) != 0;
					bool newstate = (keys[next][index] & keymask) != 0;
					if (oldstate != newstate) {
						handleButton(i, newstate);
					}
				}
				for (int i=8;i<=12;++i) {
					bool oldstate = (mask[idx] & (1 << i)) != 0;
					bool newstate = (mask[next] & (1 << i)) != 0;
					if (oldstate != newstate) {
						handleButton(0x110 + i, newstate);
					}
				}
			}
		}
	}
	XCloseDisplay(display);
}

void GlobalShortcutX::inputReadyRead(int) {
#ifdef Q_OS_LINUX
	struct input_event ev;

	if (bNeedRemap)
		remap();

	QFile *f=qobject_cast<QFile *>(sender()->parent());
	if (!f)
		return;

	bool found = false;

	while (f->read(reinterpret_cast<char *>(&ev), sizeof(ev)) == sizeof(ev)) {
		found = true;
		if (ev.type != EV_KEY)
			continue;
		bool down;
		switch (ev.value) {
			case 0:
				down = false;
				break;
			case 1:
				down = true;
				break;
			default:
				continue;
		}
		int evtcode = ev.code + 8;
		handleButton(evtcode, down);
	}

	if (! found) {
		int fd = f->handle();
		int version = 0;
		if ((ioctl(fd, EVIOCGVERSION, &version) < 0) || (((version >> 16) & 0xFF) < 1)) {
			qWarning("GlobalShortcutX: Removing dead input device %s", qPrintable(f->fileName()));
			qmInputDevices.remove(f->fileName());
			delete f;
		}
	}
#endif
}

#define test_bit(bit, array)    (array[bit/8] & (1<<(bit%8)))

void GlobalShortcutX::directoryChanged(const QString &dir) {
#ifdef Q_OS_LINUX
	QDir d(dir, QLatin1String("event*"), 0, QDir::System);
	foreach(QFileInfo fi, d.entryInfoList()) {
		QString path = fi.absoluteFilePath();
		if (! qmInputDevices.contains(path)) {
			QFile *f = new QFile(path, this);
			if (f->open(QIODevice::ReadOnly)) {
				int fd = f->handle();
				int version;
				char name[256];
				uint8_t events[EV_MAX/8 + 1];
				memset(events, 0, sizeof(events));
				if ((ioctl(fd, EVIOCGVERSION, &version) >= 0) && (ioctl(fd, EVIOCGNAME(sizeof(name)), name)>=0) && (ioctl(fd, EVIOCGBIT(0,sizeof(events)), &events) >= 0) && test_bit(EV_KEY, events) && (((version >> 16) & 0xFF) > 0)) {
					name[255]=0;
					qWarning("GlobalShortcutX: %s: %s", qPrintable(f->fileName()), name);
					fcntl(f->handle(), F_SETFL, O_NONBLOCK);
					connect(new QSocketNotifier(f->handle(), QSocketNotifier::Read, f), SIGNAL(activated(int)), this, SLOT(inputReadyRead(int)));
					qmInputDevices.insert(f->fileName(), f);
				} else {
					delete f;
				}
			} else {
				delete f;
			}
		}
	}
#endif
}

QString GlobalShortcutX::buttonName(const QVariant &v) {
	bool ok;
	unsigned int key=v.toUInt(&ok);
	if (!ok)
		return QString();
	if ((key < 0x118) || (key >= 0x128)) {
		KeySym ks=XKeycodeToKeysym(QX11Info::display(), static_cast<KeyCode>(key), 0);
		if (ks == NoSymbol) {
			return QLatin1String("0x")+QString::number(key,16);
		} else {
			const char *str=XKeysymToString(ks);
			if (strlen(str) == 0) {
				return QLatin1String("KS0x")+QString::number(ks, 16);
			} else {
				return QLatin1String(str);
			}
		}
	} else {
		return tr("Mouse %1").arg(key-0x118);
	}
}
<commit_msg>Possible support for key suppression with XEvie, but untested as Xevie itself is broken on i386<commit_after>/* Copyright (C) 2005-2008, Thorvald Natvig <thorvald@natvig.com>

   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:

   - Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
   - Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.
   - Neither the name of the Mumble Developers nor the names of its
     contributors may be used to endorse or promote products derived from this
     software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "GlobalShortcut_unix.h"
#include "Global.h"
#include <QX11Info>
#include <X11/X.h>
#include <X11/Xlib.h>
#ifdef USE_XEVIE
#include <X11/extensions/Xevie.h>
#endif

#ifdef Q_OS_LINUX
#include <linux/input.h>
#include <fcntl.h>
#endif

GlobalShortcutEngine *GlobalShortcutEngine::platformInit() {
	return new GlobalShortcutX();
}

GlobalShortcutX::GlobalShortcutX() {
	int min, maj;
	bRunning=false;
	bXevie = false;

	display = NULL;

#ifdef Q_OS_LINUX
	QString dir = QLatin1String("/dev/input");
	QFileSystemWatcher *fsw = new QFileSystemWatcher(QStringList(dir), this);
	connect(fsw, SIGNAL(directoryChanged(const QString &)), this, SLOT(directoryChanged(const QString &)));
	directoryChanged(dir);

	if (qmInputDevices.isEmpty()) {
		delete fsw;
		qWarning("GlobalShortcutX: Unable to open any input devices under /dev/input, falling back to XEVIE");
	} else {
		return;
	}
#endif

	display = XOpenDisplay(NULL);

	if (! display) {
		qWarning("GlobalShortcutX: Unable to open dedicated display connection.");
		return;
	}

	maj = 1;
	min = 1;

#ifdef USE_XEVIE
	if (! XevieQueryVersion(display, &maj, &min)) {
		qWarning("GlobalShortcutX: XEVIE extension not found. Enable it in xorg.conf");
	} else {
		qWarning("GlobalShortcutX: XEVIE %d.%d", maj, min);

#ifdef QT_NO_DEBUG
		if (! XevieStart(display)) {
			qWarning("GlobalShortcutX: Another client is already using XEVIE");
		} else {
			XevieSelectInput(display, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
			bXevie = true;
		}
#endif
	}
#else
	qWarning("GlobalShortcutX: Not compiled with XEVIE support.");
#endif
	if (! bXevie) {
		qWarning("GlobalShortcutX: No XEVIE support, falling back to polled input. This wastes a lot of CPU resources, so please enable one of the other methods.");
	}

	bRunning=true;
	start(QThread::TimeCriticalPriority);
}

GlobalShortcutX::~GlobalShortcutX() {
	bRunning = false;
	wait();
}

void GlobalShortcutX::run() {
	fd_set in_fds;
	XEvent evt;
	struct timeval tv;

	if (bXevie) {
#ifdef USE_XEVIE
		while (bRunning) {
			if (bNeedRemap)
				remap();
			FD_ZERO(&in_fds);
			FD_SET(ConnectionNumber(display), &in_fds);
			tv.tv_sec = 0;
			tv.tv_usec = 100000;
			if (select(ConnectionNumber(display)+1, &in_fds, NULL, NULL, &tv)) {
				while (XPending(display)) {
					bool suppress = false;
					XNextEvent(display, &evt);

					switch (evt.type) {
						case KeyPress:
						case KeyRelease:
						case ButtonPress:
						case ButtonRelease: {
								bool down = (evt.type == KeyPress || evt.type == ButtonPress);
								int evtcode;
								if (evt.type == KeyPress || evt.type == KeyRelease)
									evtcode = evt.xkey.keycode;
								else
									evtcode = 0x118 + evt.xbutton.button;

								suppress = handleButton(evtcode, down);
							}
							break;
						default:
							qWarning("GlobalShortcutX: EVT %x", evt.type);
					}
					if (! suppress)
						XevieSendEvent(display, &evt, XEVIE_UNMODIFIED);
				}
			}
		}
		XevieEnd(display);
#endif
	} else {
		Window root = XDefaultRootWindow(display);
		Window root_ret, child_ret;
		int root_x, root_y;
		int win_x, win_y;
		unsigned int mask[2];
		int idx = 0;
		int next = 0;
		char keys[2][32];

		memset(keys[0], 0, 32);
		memset(keys[1], 0, 32);
		mask[0] = mask[1] = 0;

		while (bRunning) {
			if (bNeedRemap)
				remap();

			msleep(10);

			idx = next;
			next = idx ^ 1;
			if (! XQueryPointer(display, root, &root_ret, &child_ret, &root_x, &root_y, &win_x, &win_y, &mask[next]) ||
			        ! XQueryKeymap(display, keys[next])) {
				qWarning("GlobalShortcutX: Lost connection");
				bRunning = false;
			} else {
				for (int i=0;i<256;++i) {
					int index = i / 8;
					int keymask = 1 << (i % 8);
					bool oldstate = (keys[idx][index] & keymask) != 0;
					bool newstate = (keys[next][index] & keymask) != 0;
					if (oldstate != newstate) {
						handleButton(i, newstate);
					}
				}
				for (int i=8;i<=12;++i) {
					bool oldstate = (mask[idx] & (1 << i)) != 0;
					bool newstate = (mask[next] & (1 << i)) != 0;
					if (oldstate != newstate) {
						handleButton(0x110 + i, newstate);
					}
				}
			}
		}
	}
	XCloseDisplay(display);
}

void GlobalShortcutX::inputReadyRead(int) {
#ifdef Q_OS_LINUX
	struct input_event ev;

	if (bNeedRemap)
		remap();

	QFile *f=qobject_cast<QFile *>(sender()->parent());
	if (!f)
		return;

	bool found = false;

	while (f->read(reinterpret_cast<char *>(&ev), sizeof(ev)) == sizeof(ev)) {
		found = true;
		if (ev.type != EV_KEY)
			continue;
		bool down;
		switch (ev.value) {
			case 0:
				down = false;
				break;
			case 1:
				down = true;
				break;
			default:
				continue;
		}
		int evtcode = ev.code + 8;
		handleButton(evtcode, down);
	}

	if (! found) {
		int fd = f->handle();
		int version = 0;
		if ((ioctl(fd, EVIOCGVERSION, &version) < 0) || (((version >> 16) & 0xFF) < 1)) {
			qWarning("GlobalShortcutX: Removing dead input device %s", qPrintable(f->fileName()));
			qmInputDevices.remove(f->fileName());
			delete f;
		}
	}
#endif
}

#define test_bit(bit, array)    (array[bit/8] & (1<<(bit%8)))

void GlobalShortcutX::directoryChanged(const QString &dir) {
#ifdef Q_OS_LINUX
	QDir d(dir, QLatin1String("event*"), 0, QDir::System);
	foreach(QFileInfo fi, d.entryInfoList()) {
		QString path = fi.absoluteFilePath();
		if (! qmInputDevices.contains(path)) {
			QFile *f = new QFile(path, this);
			if (f->open(QIODevice::ReadOnly)) {
				int fd = f->handle();
				int version;
				char name[256];
				uint8_t events[EV_MAX/8 + 1];
				memset(events, 0, sizeof(events));
				if ((ioctl(fd, EVIOCGVERSION, &version) >= 0) && (ioctl(fd, EVIOCGNAME(sizeof(name)), name)>=0) && (ioctl(fd, EVIOCGBIT(0,sizeof(events)), &events) >= 0) && test_bit(EV_KEY, events) && (((version >> 16) & 0xFF) > 0)) {
					name[255]=0;
					qWarning("GlobalShortcutX: %s: %s", qPrintable(f->fileName()), name);
					fcntl(f->handle(), F_SETFL, O_NONBLOCK);
					connect(new QSocketNotifier(f->handle(), QSocketNotifier::Read, f), SIGNAL(activated(int)), this, SLOT(inputReadyRead(int)));
					qmInputDevices.insert(f->fileName(), f);
				} else {
					delete f;
				}
			} else {
				delete f;
			}
		}
	}
#endif
}

QString GlobalShortcutX::buttonName(const QVariant &v) {
	bool ok;
	unsigned int key=v.toUInt(&ok);
	if (!ok)
		return QString();
	if ((key < 0x118) || (key >= 0x128)) {
		KeySym ks=XKeycodeToKeysym(QX11Info::display(), static_cast<KeyCode>(key), 0);
		if (ks == NoSymbol) {
			return QLatin1String("0x")+QString::number(key,16);
		} else {
			const char *str=XKeysymToString(ks);
			if (strlen(str) == 0) {
				return QLatin1String("KS0x")+QString::number(ks, 16);
			} else {
				return QLatin1String(str);
			}
		}
	} else {
		return tr("Mouse %1").arg(key-0x118);
	}
}
<|endoftext|>


<commit_before>/*
   RichardsonLucy.cxx

   Author:      Benjamin A. Thomas

   Copyright 2015 Institute of Nuclear Medicine, University College London.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   This program implements the Richardson-Lucy (RL) partial volume correction
   technique. Please cite the following paper:

	Tohka, J. and Reilhac A., (2008). "Deconvolution-based partial volume
	correction in Raclopride-PET and Monte Carlo comparison to MR-based
	method", NeuroImage, vol. 39. 1570--1584.

 */

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include <metaCommand.h>

#include "petpvcRLPVCImageFilter.h"

const char * const VERSION_NO = "0.0.1";
const char * const AUTHOR = "Benjamin A. Thomas";
const char * const APP_TITLE = "Richardson-Lucy (RL) PVC";

typedef itk::Vector<float, 3> VectorType;
typedef itk::Image<float, 3> PETImageType;

typedef itk::ImageFileReader<PETImageType> PETReaderType;
typedef itk::ImageFileWriter<PETImageType> PETWriterType;

//Produces the text for the acknowledgments dialog in Slicer.
std::string getAcknowledgments(void);

int main(int argc, char *argv[])
{

    typedef petpvc::RichardsonLucyPVCImageFilter< PETImageType >  FilterType;

    //Setting up command line argument list.
    MetaCommand command;

    command.SetVersion(VERSION_NO);
    command.SetAuthor(AUTHOR);
    command.SetName(APP_TITLE);
    command.SetDescription(
        "Performs Richardson-Lucy (RL) partial volume correction");

    std::string sAcks = getAcknowledgments();
    command.SetAcknowledgments(sAcks.c_str());

    command.SetCategory("PETPVC");

    command.AddField("petfile", "PET filename", MetaCommand::IMAGE, MetaCommand::DATA_IN);
    command.AddField("outputfile", "output filename", MetaCommand::IMAGE, MetaCommand::DATA_OUT);

    command.SetOption("FWHMx", "x", true,
                      "The full-width at half maximum in mm along x-axis");
    command.AddOptionField("FWHMx", "X", MetaCommand::FLOAT, true, "");

    command.SetOption("FWHMy", "y", true,
                      "The full-width at half maximum in mm along y-axis");
    command.AddOptionField("FWHMy", "Y", MetaCommand::FLOAT, true, "");

    command.SetOption("FWHMz", "z", true,
                      "The full-width at half maximum in mm along z-axis");
    command.AddOptionField("FWHMz", "Z", MetaCommand::FLOAT, true, "");

    command.SetOption("Iterations", "i", false, "Number of iterations");
    command.SetOptionLongTag("Iterations", "iter");
    command.AddOptionField("Iterations", "Val", MetaCommand::INT, false, "10");

    //command.SetOption("Stop", "s", false, "Stopping criterion");
    //command.SetOptionLongTag("Stop", "stop");
    //command.AddOptionField("Stop", "stopval", MetaCommand::FLOAT, false, "-3e+6");

    command.SetOption("debug", "d", false,"Prints debug information");
    command.SetOptionLongTag("debug", "debug");

    //Parse command line.
    if (!command.Parse(argc, argv)) {
        return EXIT_FAILURE;
    }

    //Get image filenames
    std::string sPETFileName = command.GetValueAsString("petfile");
    std::string sOutputFileName = command.GetValueAsString("outputfile");

    //Get values for PSF.
    float fFWHM_x = command.GetValueAsFloat("FWHMx", "X");
    float fFWHM_y = command.GetValueAsFloat("FWHMy", "Y");
    float fFWHM_z = command.GetValueAsFloat("FWHMz", "Z");

    //Get number of iterations
    int nNumOfIters = command.GetValueAsInt("Iterations", "Val");

    //Get value for stopping criterion.
    float fStop = command.GetValueAsFloat("Stop", "stopval");

    //Make vector of FWHM in x,y and z.
    VectorType vFWHM;
    vFWHM[0] = fFWHM_x;
    vFWHM[1] = fFWHM_y;
    vFWHM[2] = fFWHM_z;

    //Toggle debug mode
    bool bDebug = command.GetValueAsBool("debug");

    //Create reader for PET image.
    PETReaderType::Pointer petReader = PETReaderType::New();
    petReader->SetFileName(sPETFileName);

    //Try to read PET.
    try {
        petReader->Update();
    } catch (itk::ExceptionObject & err) {
        std::cerr << "[Error]\tCannot read PET input file: " << sPETFileName
                  << std::endl;
        return EXIT_FAILURE;
    }

    //Calculate the variance for a given FWHM.
    VectorType vVariance;
    vVariance = vFWHM / (2.0 * sqrt(2.0 * log(2.0)));
    //std::cout << vVariance << std::endl;

    VectorType vVoxelSize = petReader->GetOutput()->GetSpacing();
    //std::cout << vVoxelSize << std::endl;

    vVariance[0] = pow(vVariance[0], 2);
    vVariance[1] = pow(vVariance[1], 2);
    vVariance[2] = pow(vVariance[2], 2);

    FilterType::Pointer rlFilter = FilterType::New();
    rlFilter->SetInput( petReader->GetOutput() );
    rlFilter->SetPSF(vVariance);
    rlFilter->SetIterations( nNumOfIters );
    //rlFilter->SetStoppingCond( fStop );
    rlFilter->SetVerbose ( bDebug );

    //Perform RL.
    try {
        rlFilter->Update();
    } catch (itk::ExceptionObject & err) {
        std::cerr << "[Error]\tfailure applying Richardson-Lucy on: " << sPETFileName
                  << "\n" << err
                  << std::endl;
        return EXIT_FAILURE;
    }

    PETWriterType::Pointer petWriter = PETWriterType::New();
    petWriter->SetFileName(sOutputFileName);
    petWriter->SetInput( rlFilter->GetOutput() );

    try {
        petWriter->Update();
    } catch (itk::ExceptionObject & err) {
        std::cerr << "\n[Error]\tCannot write output file: " << sOutputFileName
                  << std::endl;

        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

std::string getAcknowledgments(void)
{
    //Produces acknowledgments string for 3DSlicer.
    std::string sAck = "This program implements the Richardson-Lucy (RL) partial volume correction technique. Please cite the following paper:\n"
                       "\tTohka, J. and Reilhac A., (2008). \"Deconvolution-based partial volume correction in Raclopride-PET\n\tand Monte Carlo comparison to MR-based method\", NeuroImage, vol. 39. 1570--1584.";

    return sAck;
}

<commit_msg>Update RichardsonLucy.cxx<commit_after>/*
   RichardsonLucy.cxx

   Author:      Benjamin A. Thomas

   Copyright 2015 Clinical Imaging Research Centre, A*STAR-NUS.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   This program implements the Richardson-Lucy (RL) partial volume correction
   technique. Please cite the following paper:

	Tohka, J. and Reilhac A., (2008). "Deconvolution-based partial volume
	correction in Raclopride-PET and Monte Carlo comparison to MR-based
	method", NeuroImage, vol. 39. 1570--1584.

 */

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include <metaCommand.h>

#include "petpvcRLPVCImageFilter.h"

const char * const VERSION_NO = "0.0.1";
const char * const AUTHOR = "Benjamin A. Thomas";
const char * const APP_TITLE = "Richardson-Lucy (RL) PVC";

typedef itk::Vector<float, 3> VectorType;
typedef itk::Image<float, 3> PETImageType;

typedef itk::ImageFileReader<PETImageType> PETReaderType;
typedef itk::ImageFileWriter<PETImageType> PETWriterType;

//Produces the text for the acknowledgments dialog in Slicer.
std::string getAcknowledgments(void);

int main(int argc, char *argv[])
{

    typedef petpvc::RichardsonLucyPVCImageFilter< PETImageType >  FilterType;

    //Setting up command line argument list.
    MetaCommand command;

    command.SetVersion(VERSION_NO);
    command.SetAuthor(AUTHOR);
    command.SetName(APP_TITLE);
    command.SetDescription(
        "Performs Richardson-Lucy (RL) partial volume correction");

    std::string sAcks = getAcknowledgments();
    command.SetAcknowledgments(sAcks.c_str());

    command.SetCategory("PETPVC");

    command.AddField("petfile", "PET filename", MetaCommand::IMAGE, MetaCommand::DATA_IN);
    command.AddField("outputfile", "output filename", MetaCommand::IMAGE, MetaCommand::DATA_OUT);

    command.SetOption("FWHMx", "x", true,
                      "The full-width at half maximum in mm along x-axis");
    command.AddOptionField("FWHMx", "X", MetaCommand::FLOAT, true, "");

    command.SetOption("FWHMy", "y", true,
                      "The full-width at half maximum in mm along y-axis");
    command.AddOptionField("FWHMy", "Y", MetaCommand::FLOAT, true, "");

    command.SetOption("FWHMz", "z", true,
                      "The full-width at half maximum in mm along z-axis");
    command.AddOptionField("FWHMz", "Z", MetaCommand::FLOAT, true, "");

    command.SetOption("Iterations", "i", false, "Number of iterations");
    command.SetOptionLongTag("Iterations", "iter");
    command.AddOptionField("Iterations", "Val", MetaCommand::INT, false, "10");

    //command.SetOption("Stop", "s", false, "Stopping criterion");
    //command.SetOptionLongTag("Stop", "stop");
    //command.AddOptionField("Stop", "stopval", MetaCommand::FLOAT, false, "-3e+6");

    command.SetOption("debug", "d", false,"Prints debug information");
    command.SetOptionLongTag("debug", "debug");

    //Parse command line.
    if (!command.Parse(argc, argv)) {
        return EXIT_FAILURE;
    }

    //Get image filenames
    std::string sPETFileName = command.GetValueAsString("petfile");
    std::string sOutputFileName = command.GetValueAsString("outputfile");

    //Get values for PSF.
    float fFWHM_x = command.GetValueAsFloat("FWHMx", "X");
    float fFWHM_y = command.GetValueAsFloat("FWHMy", "Y");
    float fFWHM_z = command.GetValueAsFloat("FWHMz", "Z");

    //Get number of iterations
    int nNumOfIters = command.GetValueAsInt("Iterations", "Val");

    //Get value for stopping criterion.
    float fStop = command.GetValueAsFloat("Stop", "stopval");

    //Make vector of FWHM in x,y and z.
    VectorType vFWHM;
    vFWHM[0] = fFWHM_x;
    vFWHM[1] = fFWHM_y;
    vFWHM[2] = fFWHM_z;

    //Toggle debug mode
    bool bDebug = command.GetValueAsBool("debug");

    //Create reader for PET image.
    PETReaderType::Pointer petReader = PETReaderType::New();
    petReader->SetFileName(sPETFileName);

    //Try to read PET.
    try {
        petReader->Update();
    } catch (itk::ExceptionObject & err) {
        std::cerr << "[Error]\tCannot read PET input file: " << sPETFileName
                  << std::endl;
        return EXIT_FAILURE;
    }

    //Calculate the variance for a given FWHM.
    VectorType vVariance;
    vVariance = vFWHM / (2.0 * sqrt(2.0 * log(2.0)));
    //std::cout << vVariance << std::endl;

    VectorType vVoxelSize = petReader->GetOutput()->GetSpacing();
    //std::cout << vVoxelSize << std::endl;

    vVariance[0] = pow(vVariance[0], 2);
    vVariance[1] = pow(vVariance[1], 2);
    vVariance[2] = pow(vVariance[2], 2);

    FilterType::Pointer rlFilter = FilterType::New();
    rlFilter->SetInput( petReader->GetOutput() );
    rlFilter->SetPSF(vVariance);
    rlFilter->SetIterations( nNumOfIters );
    //rlFilter->SetStoppingCond( fStop );
    rlFilter->SetVerbose ( bDebug );

    //Perform RL.
    try {
        rlFilter->Update();
    } catch (itk::ExceptionObject & err) {
        std::cerr << "[Error]\tfailure applying Richardson-Lucy on: " << sPETFileName
                  << "\n" << err
                  << std::endl;
        return EXIT_FAILURE;
    }

    PETWriterType::Pointer petWriter = PETWriterType::New();
    petWriter->SetFileName(sOutputFileName);
    petWriter->SetInput( rlFilter->GetOutput() );

    try {
        petWriter->Update();
    } catch (itk::ExceptionObject & err) {
        std::cerr << "\n[Error]\tCannot write output file: " << sOutputFileName
                  << std::endl;

        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

std::string getAcknowledgments(void)
{
    //Produces acknowledgments string for 3DSlicer.
    std::string sAck = "This program implements the Richardson-Lucy (RL) partial volume correction technique. Please cite the following paper:\n"
                       "\tTohka, J. and Reilhac A., (2008). \"Deconvolution-based partial volume correction in Raclopride-PET\n\tand Monte Carlo comparison to MR-based method\", NeuroImage, vol. 39. 1570--1584.";

    return sAck;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <grp.h>
#include <paths.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "debugger.h"
#include "jni_internal.h"
#include "JniConstants.h"
#include "JNIHelp.h"
#include "ScopedLocalRef.h"
#include "ScopedPrimitiveArray.h"
#include "ScopedUtfChars.h"
#include "thread.h"

#if defined(HAVE_PRCTL)
#include <sys/prctl.h>
#endif

namespace art {

static pid_t gSystemServerPid = 0;

static void Zygote_nativeExecShell(JNIEnv* env, jclass, jstring javaCommand) {
  ScopedUtfChars command(env, javaCommand);
  if (command.c_str() == NULL) {
    return;
  }
  const char* argp[] = {_PATH_BSHELL, "-c", command.c_str(), NULL};
  LOG(INFO) << "Exec: " << argp[0] << ' ' << argp[1] << ' ' << argp[2];

  execv(_PATH_BSHELL, const_cast<char**>(argp));
  exit(127);
}

// This signal handler is for zygote mode, since the zygote must reap its children
static void SigChldHandler(int /*signal_number*/) {
  pid_t pid;
  int status;

  while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
     // Log process-death status that we care about.  In general it is
     // not safe to call LOG(...) from a signal handler because of
     // possible reentrancy.  However, we know a priori that the
     // current implementation of LOG() is safe to call from a SIGCHLD
     // handler in the zygote process.  If the LOG() implementation
     // changes its locking strategy or its use of syscalls within the
     // lazy-init critical section, its use here may become unsafe.
    if (WIFEXITED(status)) {
      if (WEXITSTATUS(status)) {
        LOG(INFO) << "Process " << pid << " exited cleanly (" << WEXITSTATUS(status) << ")";
      } else if (false) {
        LOG(INFO) << "Process " << pid << " exited cleanly (" << WEXITSTATUS(status) << ")";
      }
    } else if (WIFSIGNALED(status)) {
      if (WTERMSIG(status) != SIGKILL) {
        LOG(INFO) << "Process " << pid << " terminated by signal (" << WTERMSIG(status) << ")";
      } else if (false) {
        LOG(INFO) << "Process " << pid << " terminated by signal (" << WTERMSIG(status) << ")";
      }
#ifdef WCOREDUMP
      if (WCOREDUMP(status)) {
        LOG(INFO) << "Process " << pid << " dumped core";
      }
#endif /* ifdef WCOREDUMP */
    }

    // If the just-crashed process is the system_server, bring down zygote
    // so that it is restarted by init and system server will be restarted
    // from there.
    if (pid == gSystemServerPid) {
      LOG(ERROR) << "Exit zygote because system server (" << pid << ") has terminated";
      kill(getpid(), SIGKILL);
    }
  }

  if (pid < 0) {
    PLOG(WARNING) << "Zygote SIGCHLD error in waitpid";
  }
}

// Configures the SIGCHLD handler for the zygote process. This is configured
// very late, because earlier in the runtime we may fork() and exec()
// other processes, and we want to waitpid() for those rather than
// have them be harvested immediately.
//
// This ends up being called repeatedly before each fork(), but there's
// no real harm in that.
static void SetSigChldHandler() {
  struct sigaction sa;
  memset(&sa, 0, sizeof(sa));
  sa.sa_handler = SigChldHandler;

  int err = sigaction(SIGCHLD, &sa, NULL);
  if (err < 0) {
    PLOG(WARNING) << "Error setting SIGCHLD handler";
  }
}

// Sets the SIGCHLD handler back to default behavior in zygote children.
static void UnsetSigChldHandler() {
  struct sigaction sa;
  memset(&sa, 0, sizeof(sa));
  sa.sa_handler = SIG_DFL;

  int err = sigaction(SIGCHLD, &sa, NULL);
  if (err < 0) {
    PLOG(WARNING) << "Error unsetting SIGCHLD handler";
  }
}

// Calls POSIX setgroups() using the int[] object as an argument.
// A NULL argument is tolerated.
static int SetGids(JNIEnv* env, jintArray javaGids) {
  if (javaGids == NULL) {
    return 0;
  }

  COMPILE_ASSERT(sizeof(gid_t) == sizeof(jint), sizeof_gid_and_jint_are_differerent);
  ScopedIntArrayRO gids(env, javaGids);
  if (gids.get() == NULL) {
    return -1;
  }
  return setgroups(gids.size(), (const gid_t *) &gids[0]);
}

// Sets the resource limits via setrlimit(2) for the values in the
// two-dimensional array of integers that's passed in. The second dimension
// contains a tuple of length 3: (resource, rlim_cur, rlim_max). NULL is
// treated as an empty array.
//
// -1 is returned on error.
static int SetRLimits(JNIEnv* env, jobjectArray javaRlimits) {
  if (javaRlimits == NULL) {
    return 0;
  }

  rlimit rlim;
  memset(&rlim, 0, sizeof(rlim));

  for (int i = 0; i < env->GetArrayLength(javaRlimits); i++) {
    ScopedLocalRef<jobject> javaRlimitObject(env, env->GetObjectArrayElement(javaRlimits, i));
    ScopedIntArrayRO javaRlimit(env, reinterpret_cast<jintArray>(javaRlimitObject.get()));
    if (javaRlimit.size() != 3) {
      LOG(ERROR) << "rlimits array must have a second dimension of size 3";
      return -1;
    }

    rlim.rlim_cur = javaRlimit[1];
    rlim.rlim_max = javaRlimit[2];

    int err = setrlimit(javaRlimit[0], &rlim);
    if (err < 0) {
      return -1;
    }
  }
  return 0;
}

#if defined(HAVE_ANDROID_OS)
static void SetCapabilities(int64_t permitted, int64_t effective) {
  __user_cap_header_struct capheader;
  __user_cap_data_struct capdata;

  memset(&capheader, 0, sizeof(capheader));
  memset(&capdata, 0, sizeof(capdata));

  capheader.version = _LINUX_CAPABILITY_VERSION;
  capheader.pid = 0;

  capdata.effective = effective;
  capdata.permitted = permitted;

  if (capset(&capheader, &capdata) != 0) {
    PLOG(FATAL) << "capset(" << permitted << ", " << effective << ") failed";
  }
}
#else
static void SetCapabilities(int64_t, int64_t) {}
#endif

static void EnableDebugFeatures(uint32_t debug_flags) {
  // Must match values in dalvik.system.Zygote.
  enum {
    DEBUG_ENABLE_DEBUGGER           = 1,
    DEBUG_ENABLE_CHECKJNI           = 1 << 1,
    DEBUG_ENABLE_ASSERT             = 1 << 2,
    DEBUG_ENABLE_SAFEMODE           = 1 << 3,
    DEBUG_ENABLE_JNI_LOGGING        = 1 << 4,
  };

  if ((debug_flags & DEBUG_ENABLE_CHECKJNI) != 0) {
    Runtime* runtime = Runtime::Current();
    JavaVMExt* vm = runtime->GetJavaVM();
    if (!vm->check_jni) {
      LOG(DEBUG) << "Late-enabling -Xcheck:jni";
      vm->SetCheckJniEnabled(true);
      // There's only one thread running at this point, so only one JNIEnv to fix up.
      Thread::Current()->GetJniEnv()->SetCheckJniEnabled(true);
    } else {
      LOG(DEBUG) << "Not late-enabling -Xcheck:jni (already on)";
    }
    debug_flags &= ~DEBUG_ENABLE_CHECKJNI;
  }

  if ((debug_flags & DEBUG_ENABLE_JNI_LOGGING) != 0) {
    gLogVerbosity.third_party_jni = true;
    debug_flags &= ~DEBUG_ENABLE_JNI_LOGGING;
  }

  Dbg::SetJdwpAllowed((debug_flags & DEBUG_ENABLE_DEBUGGER) != 0);
#ifdef HAVE_ANDROID_OS
  if ((debug_flags & DEBUG_ENABLE_DEBUGGER) != 0) {
    /* To let a non-privileged gdbserver attach to this
     * process, we must set its dumpable bit flag. However
     * we are not interested in generating a coredump in
     * case of a crash, so also set the coredump size to 0
     * to disable that
     */
    if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
      PLOG(ERROR) << "could not set dumpable bit flag for pid " << getpid();
    } else {
      rlimit rl;
      rl.rlim_cur = 0;
      rl.rlim_max = RLIM_INFINITY;
      if (setrlimit(RLIMIT_CORE, &rl) < 0) {
        PLOG(ERROR) << "could not disable core file generation for pid " << getpid();
      }
    }
  }
#endif
  debug_flags &= ~DEBUG_ENABLE_DEBUGGER;

  // These two are for backwards compatibility with Dalvik.
  debug_flags &= ~DEBUG_ENABLE_ASSERT;
  debug_flags &= ~DEBUG_ENABLE_SAFEMODE;

  if (debug_flags != 0) {
    LOG(ERROR) << StringPrintf("Unknown bits set in debug_flags: %#x", debug_flags);
  }
}

#ifdef HAVE_ANDROID_OS
extern "C" int gMallocLeakZygoteChild;
#endif

// Utility routine to fork zygote and specialize the child process.
static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
                                     jint debug_flags, jobjectArray javaRlimits,
                                     jlong permittedCapabilities, jlong effectiveCapabilities) {
  Runtime* runtime = Runtime::Current();
  CHECK(runtime->IsZygote()) << "runtime instance not started with -Xzygote";
  if (false) { // TODO: do we need do anything special like !dvmGcPreZygoteFork()?
    LOG(FATAL) << "pre-fork heap failed";
  }

  SetSigChldHandler();

  // Grab thread before fork potentially makes Thread::pthread_key_self_ unusable.
  Thread* self = Thread::Current();

  // dvmDumpLoaderStats("zygote");  // TODO: ?
  pid_t pid = fork();

  if (pid == 0) {
    // The child process

#ifdef HAVE_ANDROID_OS
    gMallocLeakZygoteChild = 1;

    // keep caps across UID change, unless we're staying root */
    if (uid != 0) {
      int err = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
      if (err < 0) {
        PLOG(FATAL) << "cannot PR_SET_KEEPCAPS";
      }
    }
#endif // HAVE_ANDROID_OS

    int err = SetGids(env, javaGids);
    if (err < 0) {
        PLOG(FATAL) << "setgroups failed";
    }

    err = SetRLimits(env, javaRlimits);
    if (err < 0) {
      PLOG(FATAL) << "setrlimit failed";
    }

    err = setgid(gid);
    if (err < 0) {
      PLOG(FATAL) << "setgid(" << gid << ") failed";
    }

    err = setuid(uid);
    if (err < 0) {
      PLOG(FATAL) << "setuid(" << uid << ") failed";
    }

    SetCapabilities(permittedCapabilities, effectiveCapabilities);

    // Our system thread ID, etc, has changed so reset Thread state.
    self->InitAfterFork();

    EnableDebugFeatures(debug_flags);

    UnsetSigChldHandler();
    runtime->DidForkFromZygote();
  } else if (pid > 0) {
    // the parent process
  }
  return pid;
}

static jint Zygote_nativeForkAndSpecialize(JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
                                           jint debug_flags, jobjectArray rlimits) {
  return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags, rlimits, 0, 0);
}

static jint Zygote_nativeForkSystemServer(JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
                                          jint debug_flags, jobjectArray rlimits,
                                          jlong permittedCapabilities, jlong effectiveCapabilities) {
  pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
                                      debug_flags, rlimits,
                                      permittedCapabilities, effectiveCapabilities);
  if (pid > 0) {
      // The zygote process checks whether the child process has died or not.
      LOG(INFO) << "System server process " << pid << " has been created";
      gSystemServerPid = pid;
      // There is a slight window that the system server process has crashed
      // but it went unnoticed because we haven't published its pid yet. So
      // we recheck here just to make sure that all is well.
      int status;
      if (waitpid(pid, &status, WNOHANG) == pid) {
          LOG(FATAL) << "System server process " << pid << " has died. Restarting Zygote!";
      }
  }
  return pid;
}

static JNINativeMethod gMethods[] = {
  NATIVE_METHOD(Zygote, nativeExecShell, "(Ljava/lang/String;)V"),
  //NATIVE_METHOD(Zygote, nativeFork, "()I"),
  NATIVE_METHOD(Zygote, nativeForkAndSpecialize, "(II[II[[I)I"),
  NATIVE_METHOD(Zygote, nativeForkSystemServer, "(II[II[[IJJ)I"),
};

void register_dalvik_system_Zygote(JNIEnv* env) {
  jniRegisterNativeMethods(env, "dalvik/system/Zygote", gMethods, NELEM(gMethods));
}

}  // namespace art
<commit_msg>am b6636b8e: Add a reminder that we need to track a change in master.<commit_after>/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <grp.h>
#include <paths.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "cutils/sched_policy.h"
#include "debugger.h"
#include "jni_internal.h"
#include "JniConstants.h"
#include "JNIHelp.h"
#include "ScopedLocalRef.h"
#include "ScopedPrimitiveArray.h"
#include "ScopedUtfChars.h"
#include "thread.h"

#if defined(HAVE_PRCTL)
#include <sys/prctl.h>
#endif

namespace art {

static pid_t gSystemServerPid = 0;

static void Zygote_nativeExecShell(JNIEnv* env, jclass, jstring javaCommand) {
  ScopedUtfChars command(env, javaCommand);
  if (command.c_str() == NULL) {
    return;
  }
  const char* argp[] = {_PATH_BSHELL, "-c", command.c_str(), NULL};
  LOG(INFO) << "Exec: " << argp[0] << ' ' << argp[1] << ' ' << argp[2];

  execv(_PATH_BSHELL, const_cast<char**>(argp));
  exit(127);
}

// This signal handler is for zygote mode, since the zygote must reap its children
static void SigChldHandler(int /*signal_number*/) {
  pid_t pid;
  int status;

  while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
     // Log process-death status that we care about.  In general it is
     // not safe to call LOG(...) from a signal handler because of
     // possible reentrancy.  However, we know a priori that the
     // current implementation of LOG() is safe to call from a SIGCHLD
     // handler in the zygote process.  If the LOG() implementation
     // changes its locking strategy or its use of syscalls within the
     // lazy-init critical section, its use here may become unsafe.
    if (WIFEXITED(status)) {
      if (WEXITSTATUS(status)) {
        LOG(INFO) << "Process " << pid << " exited cleanly (" << WEXITSTATUS(status) << ")";
      } else if (false) {
        LOG(INFO) << "Process " << pid << " exited cleanly (" << WEXITSTATUS(status) << ")";
      }
    } else if (WIFSIGNALED(status)) {
      if (WTERMSIG(status) != SIGKILL) {
        LOG(INFO) << "Process " << pid << " terminated by signal (" << WTERMSIG(status) << ")";
      } else if (false) {
        LOG(INFO) << "Process " << pid << " terminated by signal (" << WTERMSIG(status) << ")";
      }
#ifdef WCOREDUMP
      if (WCOREDUMP(status)) {
        LOG(INFO) << "Process " << pid << " dumped core";
      }
#endif /* ifdef WCOREDUMP */
    }

    // If the just-crashed process is the system_server, bring down zygote
    // so that it is restarted by init and system server will be restarted
    // from there.
    if (pid == gSystemServerPid) {
      LOG(ERROR) << "Exit zygote because system server (" << pid << ") has terminated";
      kill(getpid(), SIGKILL);
    }
  }

  if (pid < 0) {
    PLOG(WARNING) << "Zygote SIGCHLD error in waitpid";
  }
}

// Configures the SIGCHLD handler for the zygote process. This is configured
// very late, because earlier in the runtime we may fork() and exec()
// other processes, and we want to waitpid() for those rather than
// have them be harvested immediately.
//
// This ends up being called repeatedly before each fork(), but there's
// no real harm in that.
static void SetSigChldHandler() {
  struct sigaction sa;
  memset(&sa, 0, sizeof(sa));
  sa.sa_handler = SigChldHandler;

  int err = sigaction(SIGCHLD, &sa, NULL);
  if (err < 0) {
    PLOG(WARNING) << "Error setting SIGCHLD handler";
  }
}

// Sets the SIGCHLD handler back to default behavior in zygote children.
static void UnsetSigChldHandler() {
  struct sigaction sa;
  memset(&sa, 0, sizeof(sa));
  sa.sa_handler = SIG_DFL;

  int err = sigaction(SIGCHLD, &sa, NULL);
  if (err < 0) {
    PLOG(WARNING) << "Error unsetting SIGCHLD handler";
  }
}

// Calls POSIX setgroups() using the int[] object as an argument.
// A NULL argument is tolerated.
static int SetGids(JNIEnv* env, jintArray javaGids) {
  if (javaGids == NULL) {
    return 0;
  }

  COMPILE_ASSERT(sizeof(gid_t) == sizeof(jint), sizeof_gid_and_jint_are_differerent);
  ScopedIntArrayRO gids(env, javaGids);
  if (gids.get() == NULL) {
    return -1;
  }
  return setgroups(gids.size(), (const gid_t *) &gids[0]);
}

// Sets the resource limits via setrlimit(2) for the values in the
// two-dimensional array of integers that's passed in. The second dimension
// contains a tuple of length 3: (resource, rlim_cur, rlim_max). NULL is
// treated as an empty array.
//
// -1 is returned on error.
static int SetRLimits(JNIEnv* env, jobjectArray javaRlimits) {
  if (javaRlimits == NULL) {
    return 0;
  }

  rlimit rlim;
  memset(&rlim, 0, sizeof(rlim));

  for (int i = 0; i < env->GetArrayLength(javaRlimits); i++) {
    ScopedLocalRef<jobject> javaRlimitObject(env, env->GetObjectArrayElement(javaRlimits, i));
    ScopedIntArrayRO javaRlimit(env, reinterpret_cast<jintArray>(javaRlimitObject.get()));
    if (javaRlimit.size() != 3) {
      LOG(ERROR) << "rlimits array must have a second dimension of size 3";
      return -1;
    }

    rlim.rlim_cur = javaRlimit[1];
    rlim.rlim_max = javaRlimit[2];

    int err = setrlimit(javaRlimit[0], &rlim);
    if (err < 0) {
      return -1;
    }
  }
  return 0;
}

#if defined(HAVE_ANDROID_OS)
static void SetCapabilities(int64_t permitted, int64_t effective) {
  __user_cap_header_struct capheader;
  __user_cap_data_struct capdata;

  memset(&capheader, 0, sizeof(capheader));
  memset(&capdata, 0, sizeof(capdata));

  capheader.version = _LINUX_CAPABILITY_VERSION;
  capheader.pid = 0;

  capdata.effective = effective;
  capdata.permitted = permitted;

  if (capset(&capheader, &capdata) != 0) {
    PLOG(FATAL) << "capset(" << permitted << ", " << effective << ") failed";
  }
}
#else
static void SetCapabilities(int64_t, int64_t) {}
#endif

static void EnableDebugFeatures(uint32_t debug_flags) {
  // Must match values in dalvik.system.Zygote.
  enum {
    DEBUG_ENABLE_DEBUGGER           = 1,
    DEBUG_ENABLE_CHECKJNI           = 1 << 1,
    DEBUG_ENABLE_ASSERT             = 1 << 2,
    DEBUG_ENABLE_SAFEMODE           = 1 << 3,
    DEBUG_ENABLE_JNI_LOGGING        = 1 << 4,
  };

  if ((debug_flags & DEBUG_ENABLE_CHECKJNI) != 0) {
    Runtime* runtime = Runtime::Current();
    JavaVMExt* vm = runtime->GetJavaVM();
    if (!vm->check_jni) {
      LOG(DEBUG) << "Late-enabling -Xcheck:jni";
      vm->SetCheckJniEnabled(true);
      // There's only one thread running at this point, so only one JNIEnv to fix up.
      Thread::Current()->GetJniEnv()->SetCheckJniEnabled(true);
    } else {
      LOG(DEBUG) << "Not late-enabling -Xcheck:jni (already on)";
    }
    debug_flags &= ~DEBUG_ENABLE_CHECKJNI;
  }

  if ((debug_flags & DEBUG_ENABLE_JNI_LOGGING) != 0) {
    gLogVerbosity.third_party_jni = true;
    debug_flags &= ~DEBUG_ENABLE_JNI_LOGGING;
  }

  Dbg::SetJdwpAllowed((debug_flags & DEBUG_ENABLE_DEBUGGER) != 0);
#ifdef HAVE_ANDROID_OS
  if ((debug_flags & DEBUG_ENABLE_DEBUGGER) != 0) {
    /* To let a non-privileged gdbserver attach to this
     * process, we must set its dumpable bit flag. However
     * we are not interested in generating a coredump in
     * case of a crash, so also set the coredump size to 0
     * to disable that
     */
    if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
      PLOG(ERROR) << "could not set dumpable bit flag for pid " << getpid();
    } else {
      rlimit rl;
      rl.rlim_cur = 0;
      rl.rlim_max = RLIM_INFINITY;
      if (setrlimit(RLIMIT_CORE, &rl) < 0) {
        PLOG(ERROR) << "could not disable core file generation for pid " << getpid();
      }
    }
  }
#endif
  debug_flags &= ~DEBUG_ENABLE_DEBUGGER;

  // These two are for backwards compatibility with Dalvik.
  debug_flags &= ~DEBUG_ENABLE_ASSERT;
  debug_flags &= ~DEBUG_ENABLE_SAFEMODE;

  if (debug_flags != 0) {
    LOG(ERROR) << StringPrintf("Unknown bits set in debug_flags: %#x", debug_flags);
  }
}

#ifdef HAVE_ANDROID_OS
extern "C" int gMallocLeakZygoteChild;
#endif

// Utility routine to fork zygote and specialize the child process.
static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
                                     jint debug_flags, jobjectArray javaRlimits,
                                     jlong permittedCapabilities, jlong effectiveCapabilities) {
  Runtime* runtime = Runtime::Current();
  CHECK(runtime->IsZygote()) << "runtime instance not started with -Xzygote";
  if (false) { // TODO: do we need do anything special like !dvmGcPreZygoteFork()?
    LOG(FATAL) << "pre-fork heap failed";
  }

  SetSigChldHandler();

  // Grab thread before fork potentially makes Thread::pthread_key_self_ unusable.
  Thread* self = Thread::Current();

  // dvmDumpLoaderStats("zygote");  // TODO: ?
  pid_t pid = fork();

  if (pid == 0) {
    // The child process

#ifdef HAVE_ANDROID_OS
    gMallocLeakZygoteChild = 1;

    // keep caps across UID change, unless we're staying root */
    if (uid != 0) {
      int err = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
      if (err < 0) {
        PLOG(FATAL) << "cannot PR_SET_KEEPCAPS";
      }
    }
#endif // HAVE_ANDROID_OS

    int err = SetGids(env, javaGids);
    if (err < 0) {
        PLOG(FATAL) << "setgroups failed";
    }

    err = SetRLimits(env, javaRlimits);
    if (err < 0) {
      PLOG(FATAL) << "setrlimit failed";
    }

    err = setgid(gid);
    if (err < 0) {
      PLOG(FATAL) << "setgid(" << gid << ") failed";
    }

    err = setuid(uid);
    if (err < 0) {
      PLOG(FATAL) << "setuid(" << uid << ") failed";
    }

    SetCapabilities(permittedCapabilities, effectiveCapabilities);

#if 1
    UNIMPLEMENTED(WARNING) << "enable this code when cutils/sched_policy.h has SP_DEFAULT";
#else
    err = set_sched_policy(0, SP_DEFAULT);
    if (err < 0) {
      errno = -err;
      PLOG(FATAL) << "set_sched_policy(0, SP_DEFAULT) failed";
    }
#endif

    // Our system thread ID, etc, has changed so reset Thread state.
    self->InitAfterFork();

    EnableDebugFeatures(debug_flags);

    UnsetSigChldHandler();
    runtime->DidForkFromZygote();
  } else if (pid > 0) {
    // the parent process
  }
  return pid;
}

static jint Zygote_nativeForkAndSpecialize(JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
                                           jint debug_flags, jobjectArray rlimits) {
  return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags, rlimits, 0, 0);
}

static jint Zygote_nativeForkSystemServer(JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
                                          jint debug_flags, jobjectArray rlimits,
                                          jlong permittedCapabilities, jlong effectiveCapabilities) {
  pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
                                      debug_flags, rlimits,
                                      permittedCapabilities, effectiveCapabilities);
  if (pid > 0) {
      // The zygote process checks whether the child process has died or not.
      LOG(INFO) << "System server process " << pid << " has been created";
      gSystemServerPid = pid;
      // There is a slight window that the system server process has crashed
      // but it went unnoticed because we haven't published its pid yet. So
      // we recheck here just to make sure that all is well.
      int status;
      if (waitpid(pid, &status, WNOHANG) == pid) {
          LOG(FATAL) << "System server process " << pid << " has died. Restarting Zygote!";
      }
  }
  return pid;
}

static JNINativeMethod gMethods[] = {
  NATIVE_METHOD(Zygote, nativeExecShell, "(Ljava/lang/String;)V"),
  //NATIVE_METHOD(Zygote, nativeFork, "()I"),
  NATIVE_METHOD(Zygote, nativeForkAndSpecialize, "(II[II[[I)I"),
  NATIVE_METHOD(Zygote, nativeForkSystemServer, "(II[II[[IJJ)I"),
};

void register_dalvik_system_Zygote(JNIEnv* env) {
  jniRegisterNativeMethods(env, "dalvik/system/Zygote", gMethods, NELEM(gMethods));
}

}  // namespace art
<|endoftext|>


<commit_before>#include <QDebug>
#include <QDir>
#include <QTemporaryFile>
#include <iostream>
#include "kernel.h"
#include "geometries.h"
#include "ilwiscontext.h"
#include "grid.h"

using namespace Ilwis;
GridBlockInternal::GridBlockInternal(quint32 lines , quint32 width) :  _size(Size(lines,width,1)),_initialized(false), _loaded(false)

{
    _undef = undef<double>();
    _id = ++_blockid;
    _blockSize = _size.xsize()* _size.ysize();
}

GridBlockInternal::~GridBlockInternal() {

}

Size GridBlockInternal::size() const {
    return _size;
}

GridBlockInternal *GridBlockInternal::clone()
{
    GridBlockInternal *block = new GridBlockInternal(_size.xsize(), _size.ysize());
    block->prepare();
    block->_undef = _undef;
    block->_index = 0;
    block->_blockSize = _blockSize;
    if(!isLoaded())
        load();
    std::copy(_data.begin(), _data.end(), block->_data.begin());

    return block;

}

char *GridBlockInternal::blockAsMemory() {
    prepare();
    return (char *)&_data[0];
}

void GridBlockInternal::fill(const std::vector<double>& values) {

    if ( values.size() != _data.size())
        prepare();
    copy(values.begin(), values.end(), _data.begin());

}

quint32 GridBlockInternal::blockSize() {
    return _blockSize;
}

bool GridBlockInternal::isLoaded() const {
    return _loaded;
}

inline bool GridBlockInternal::unload() {
    if ( _tempName == sUNDEF) {
        QString name = QString("gridblock_%1").arg(_id);
        QDir localDir(context()->temporaryWorkLocation().toLocalFile());
        if ( !localDir.exists()) {
            localDir.mkpath(localDir.absolutePath());
        }
        _tempName = localDir.absolutePath() + "/" + name;
    }
    if ( _swapFile.isNull()) {
        _swapFile.reset(new QTemporaryFile(_tempName));

    }
    if(!_swapFile->open() ){
        return ERROR1(ERR_COULD_NOT_OPEN_WRITING_1,_tempName);
    }
    quint64 bytesNeeded = _data.size() * sizeof(double);
    quint64 total =_swapFile->write((char *)&_data[0], bytesNeeded);
    _swapFile->close();
    if ( total != bytesNeeded) {
        return ERROR1(ERR_COULD_NOT_OPEN_WRITING_1,_tempName);
    }
    _loaded = false;
    _initialized = false;
    _data.clear();

    return true;

}

bool GridBlockInternal::load() {
     _loaded = true;
    prepare();
    if ( _tempName == sUNDEF) {
        return true; // totaly new block; never been swapped so no load needed
    }
    quint64 bytesNeeded = _data.size() * sizeof(double);
    if(!_swapFile->open() ){
        return ERROR1(ERR_COULD_NOT_OPEN_READING_1,_tempName);
    }
    quint64 total =_swapFile->read((char *)&_data[0], bytesNeeded);

    _swapFile->close();
    if ( total != bytesNeeded) {
        _loaded = false;
        return ERROR1(ERR_COULD_NOT_OPEN_READING_1,_tempName);
    }
    return true;

}

//----------------------------------------------------------------------
Grid::Grid(const Size& sz, int maxLines) : _maxLines(maxLines){
    //Locker lock(_mutex);

    setSize(sz);
    quint64 bytesNeeded = _size.totalSize() * sizeof(double);
    quint64 mleft = context()->memoryLeft();
    _memUsed = std::min(bytesNeeded, mleft/2);
    context()->changeMemoryLeft(-_memUsed);
    int n = numberOfBlocks();
    _inMemoryIndex = std::max(1ULL, n * _memUsed / bytesNeeded);
    _blocksPerBand = n / sz.zsize();

}

quint32 Grid::blockSize(quint32 index) const {
    if ( index < _blockSizes.size() )
        return _blockSizes[index];
    return iUNDEF;
}

Grid::~Grid() {
    clear();
    context()->changeMemoryLeft(_memUsed);
}

Size Grid::size() const {
    return _size;
}

int Grid::maxLines() const
{
    return _maxLines;
}

Grid *Grid::clone(quint32 index1, quint32 index2)
{
    if ( index2 < index1){
        ERROR2(ERR_INVALID_INIT_FOR_2,TR("grid limits"),TR("clone grid"));
        return 0;
    }
    quint32 start = index1 == iUNDEF ? 0 : index1;
    quint32 end = index2 == iUNDEF ? _blocks.size() / _blocksPerBand : index2 + 1;

    Grid *grid = new Grid(Size(_size.xsize(), _size.ysize(), end - start), _maxLines);
    grid->prepare();

    quint32 startBlock = start * _blocksPerBand;
    quint32 endBlock = std::min(end * _blocksPerBand, _blocks.size());
    for(int i=startBlock, j=0; i < endBlock; ++i, ++j) {
        grid->_blocks[j] = _blocks[i]->clone();
    }
    grid->_inMemoryIndex = 1;
    grid->_memUsed = _memUsed;
    return grid;

}

void Grid::clear() {
    _size = Size();
    _blockSizes.clear();
    for(quint32 i = 0; i < _blocks.size(); ++i) {
        delete _blocks[i];
    }
    _blocks.clear();
}

double Grid::value(const Pixel &pix) {
    if ( pix.x <0 || pix.y < 0 || pix.z < 0)
        return rUNDEF;
    quint32 yoff = (qint32)pix.y % _maxLines;
    quint32 block = pix.y / _maxLines;
    quint32 bandBlocks = _blocksPerBand * pix.z;
    quint32 offset = _offsets[yoff][pix.x];
    return value(bandBlocks + block, offset);
}

inline double &Grid::value(quint32 block, int offset )  {
    if ( _blocks.size() <= _inMemoryIndex) // no cache case
        return _blocks[block]->at(offset);

    update(block);

    return _blocks[_cacheHead]->at(offset);
}

inline void Grid::setValue(quint32 block, int offset, double v ) {
    if ( _blocks.size() <= _inMemoryIndex) {
        _blocks[block]->at(offset) = v;
        return ;
    }

    if(!update(block))
        return ;

    _blocks[_cacheHead]->at(offset) = v;
}

quint32 Grid::blocks() const {
    return _blocks.size();
}

quint32 Grid::blocksPerBand() const {
    return _blocksPerBand;
}

void Grid::setBlock(quint32 block, const std::vector<double>& data, bool creation) {
    if ( _blocks.size() <= _inMemoryIndex) { // no cache case
        _blocks[block]->fill(data);
        return ;
    }
    if(!update(block, creation))
        return ;
    _blocks[_cache[block]]->fill(data);
}

char *Grid::blockAsMemory(quint32 block, bool creation) {
    if ( _blocks.size() <= _inMemoryIndex) { // no cache case
        GridBlockInternal *du = _blocks[block];
        char * p = du->blockAsMemory();
        return p;
    }

    if(!update(block, creation))
        return 0;
    GridBlockInternal *du = _blocks[_cache[block]];
    char * p = du->blockAsMemory();
    return p;

}

void Grid::setSize(const Size& sz) {
    if ( _blocks.size() != 0)
        clear();
    _size = sz;
    if ( _size.zsize() == 0)
        _size.zsize(1); // 1 grid at least in the grid;

}

bool Grid::prepare() {
    Locker lock(_mutex);
    if ( _size.isNull()|| !_size.isValid() || _maxLines == 0) {
        return ERROR0("Grid size not properly initialized");
    }

    int nblocks = numberOfBlocks();
    qint32 totalLines = _size.ysize();
    _blocks.resize(nblocks);
    _blockSizes.resize(nblocks);
    _blockOffsets.resize(nblocks);

    for(quint32 i = 0; i < _blocks.size(); ++i) {
        int linesPerBlock = std::min((qint32)_maxLines, totalLines);
        _blocks[i] = new GridBlockInternal(linesPerBlock, _size.xsize());
        _blockSizes[i] = linesPerBlock * _size.xsize();
        _blockOffsets[i] = i == 0 ? 0 : _blockOffsets[i-1] +  _blockSizes[i];
        totalLines -= _maxLines;
        if ( totalLines <= 0) // to next band
            totalLines = _size.ysize();
    }
    _offsets.resize(_maxLines);
    for(quint32 y=0; y < _maxLines; ++y) {
        _offsets[y].resize(_size.xsize());
        for(quint32 x=0; x < _size.xsize(); ++x) {
            quint64 linearPos = y * size().xsize() + x;
            _offsets[y][x] = linearPos;
        }
    }
    return true;
}

int Grid::numberOfBlocks() {
    double rblocks = (double)_size.ysize() / _maxLines;
    int nblocks = (int)rblocks;
    double rest = rblocks - nblocks;
    if ( rest >= (1.0 / ( _maxLines + 1))) {
        nblocks++;
    }
    return nblocks * _size.zsize();
}

inline bool Grid::update(quint32 block, bool creation) {
    Locker lock(_mutex);
    if ( block >= _blocks.size() )
        return false;
    if ( !_blocks[block]->isLoaded()) {
        if(!_blocks[block]->load())
            return false;
    }
    if ( creation || _cache.size() == 0) { // at create time we want to preserver the original order in memory

        if ( block > _inMemoryIndex )
            _blocks[_cache.back()]->unload();
        _cache.push_back(block);
    }
    else if ( _cache.front() != block) {
        int index = _cache.indexOf(block);
        if (index >=0) {
            _cache.removeOne(index);
        }
        _cache.push_front(block);
        _cacheHead = block; // for efficiency, no lookup what the head is
        if ( index > (int)_inMemoryIndex) {
            return _blocks[_cache[_inMemoryIndex]]->unload();
        }

    }
    return true;
}

void Grid::unload() {
    Locker lock(_mutex);
    _cache.clear();
    for(GridBlockInternal *block : _blocks) {
        block->unload();
    }
    _inMemoryIndex = 0;
}

<commit_msg>fixed issue on missing check for is3D of a pixel on value access<commit_after>#include <QDebug>
#include <QDir>
#include <QTemporaryFile>
#include <iostream>
#include "kernel.h"
#include "geometries.h"
#include "ilwiscontext.h"
#include "grid.h"

using namespace Ilwis;
GridBlockInternal::GridBlockInternal(quint32 lines , quint32 width) :  _size(Size(lines,width,1)),_initialized(false), _loaded(false)

{
    _undef = undef<double>();
    _id = ++_blockid;
    _blockSize = _size.xsize()* _size.ysize();
}

GridBlockInternal::~GridBlockInternal() {

}

Size GridBlockInternal::size() const {
    return _size;
}

GridBlockInternal *GridBlockInternal::clone()
{
    GridBlockInternal *block = new GridBlockInternal(_size.xsize(), _size.ysize());
    block->prepare();
    block->_undef = _undef;
    block->_index = 0;
    block->_blockSize = _blockSize;
    if(!isLoaded())
        load();
    std::copy(_data.begin(), _data.end(), block->_data.begin());

    return block;

}

char *GridBlockInternal::blockAsMemory() {
    prepare();
    return (char *)&_data[0];
}

void GridBlockInternal::fill(const std::vector<double>& values) {

    if ( values.size() != _data.size())
        prepare();
    copy(values.begin(), values.end(), _data.begin());

}

quint32 GridBlockInternal::blockSize() {
    return _blockSize;
}

bool GridBlockInternal::isLoaded() const {
    return _loaded;
}

inline bool GridBlockInternal::unload() {
    if ( _tempName == sUNDEF) {
        QString name = QString("gridblock_%1").arg(_id);
        QDir localDir(context()->temporaryWorkLocation().toLocalFile());
        if ( !localDir.exists()) {
            localDir.mkpath(localDir.absolutePath());
        }
        _tempName = localDir.absolutePath() + "/" + name;
    }
    if ( _swapFile.isNull()) {
        _swapFile.reset(new QTemporaryFile(_tempName));

    }
    if(!_swapFile->open() ){
        return ERROR1(ERR_COULD_NOT_OPEN_WRITING_1,_tempName);
    }
    quint64 bytesNeeded = _data.size() * sizeof(double);
    quint64 total =_swapFile->write((char *)&_data[0], bytesNeeded);
    _swapFile->close();
    if ( total != bytesNeeded) {
        return ERROR1(ERR_COULD_NOT_OPEN_WRITING_1,_tempName);
    }
    _loaded = false;
    _initialized = false;
    _data.clear();

    return true;

}

bool GridBlockInternal::load() {
     _loaded = true;
    prepare();
    if ( _tempName == sUNDEF) {
        return true; // totaly new block; never been swapped so no load needed
    }
    quint64 bytesNeeded = _data.size() * sizeof(double);
    if(!_swapFile->open() ){
        return ERROR1(ERR_COULD_NOT_OPEN_READING_1,_tempName);
    }
    quint64 total =_swapFile->read((char *)&_data[0], bytesNeeded);

    _swapFile->close();
    if ( total != bytesNeeded) {
        _loaded = false;
        return ERROR1(ERR_COULD_NOT_OPEN_READING_1,_tempName);
    }
    return true;

}

//----------------------------------------------------------------------
Grid::Grid(const Size& sz, int maxLines) : _maxLines(maxLines){
    //Locker lock(_mutex);

    setSize(sz);
    quint64 bytesNeeded = _size.totalSize() * sizeof(double);
    quint64 mleft = context()->memoryLeft();
    _memUsed = std::min(bytesNeeded, mleft/2);
    context()->changeMemoryLeft(-_memUsed);
    int n = numberOfBlocks();
    _inMemoryIndex = std::max(1ULL, n * _memUsed / bytesNeeded);
    _blocksPerBand = n / sz.zsize();

}

quint32 Grid::blockSize(quint32 index) const {
    if ( index < _blockSizes.size() )
        return _blockSizes[index];
    return iUNDEF;
}

Grid::~Grid() {
    clear();
    context()->changeMemoryLeft(_memUsed);
}

Size Grid::size() const {
    return _size;
}

int Grid::maxLines() const
{
    return _maxLines;
}

Grid *Grid::clone(quint32 index1, quint32 index2)
{
    if ( index2 < index1){
        ERROR2(ERR_INVALID_INIT_FOR_2,TR("grid limits"),TR("clone grid"));
        return 0;
    }
    quint32 start = index1 == iUNDEF ? 0 : index1;
    quint32 end = index2 == iUNDEF ? _blocks.size() / _blocksPerBand : index2 + 1;

    Grid *grid = new Grid(Size(_size.xsize(), _size.ysize(), end - start), _maxLines);
    grid->prepare();

    quint32 startBlock = start * _blocksPerBand;
    quint32 endBlock = std::min(end * _blocksPerBand, _blocks.size());
    for(int i=startBlock, j=0; i < endBlock; ++i, ++j) {
        grid->_blocks[j] = _blocks[i]->clone();
    }
    grid->_inMemoryIndex = 1;
    grid->_memUsed = _memUsed;
    return grid;

}

void Grid::clear() {
    _size = Size();
    _blockSizes.clear();
    for(quint32 i = 0; i < _blocks.size(); ++i) {
        delete _blocks[i];
    }
    _blocks.clear();
}

double Grid::value(const Pixel &pix) {
    if ( pix.x <0 || pix.y < 0 || (pix.z < 0 &&
                                   pix.is3D()))
        return rUNDEF;
    quint32 yoff = (qint32)pix.y % _maxLines;
    quint32 block = pix.y / _maxLines;
    quint32 bandBlocks = _blocksPerBand * (pix.is3D() ? pix.z : 0);
    quint32 offset = _offsets[yoff][pix.x];
    return value(bandBlocks + block, offset);
}

inline double &Grid::value(quint32 block, int offset )  {
    if ( _blocks.size() <= _inMemoryIndex) // no cache case
        return _blocks[block]->at(offset);

    update(block);

    return _blocks[_cacheHead]->at(offset);
}

inline void Grid::setValue(quint32 block, int offset, double v ) {
    if ( _blocks.size() <= _inMemoryIndex) {
        _blocks[block]->at(offset) = v;
        return ;
    }

    if(!update(block))
        return ;

    _blocks[_cacheHead]->at(offset) = v;
}

quint32 Grid::blocks() const {
    return _blocks.size();
}

quint32 Grid::blocksPerBand() const {
    return _blocksPerBand;
}

void Grid::setBlock(quint32 block, const std::vector<double>& data, bool creation) {
    if ( _blocks.size() <= _inMemoryIndex) { // no cache case
        _blocks[block]->fill(data);
        return ;
    }
    if(!update(block, creation))
        return ;
    _blocks[_cache[block]]->fill(data);
}

char *Grid::blockAsMemory(quint32 block, bool creation) {
    if ( _blocks.size() <= _inMemoryIndex) { // no cache case
        GridBlockInternal *du = _blocks[block];
        char * p = du->blockAsMemory();
        return p;
    }

    if(!update(block, creation))
        return 0;
    GridBlockInternal *du = _blocks[_cache[block]];
    char * p = du->blockAsMemory();
    return p;

}

void Grid::setSize(const Size& sz) {
    if ( _blocks.size() != 0)
        clear();
    _size = sz;
    if ( _size.zsize() == 0)
        _size.zsize(1); // 1 grid at least in the grid;

}

bool Grid::prepare() {
    Locker lock(_mutex);
    if ( _size.isNull()|| !_size.isValid() || _maxLines == 0) {
        return ERROR0("Grid size not properly initialized");
    }

    int nblocks = numberOfBlocks();
    qint32 totalLines = _size.ysize();
    _blocks.resize(nblocks);
    _blockSizes.resize(nblocks);
    _blockOffsets.resize(nblocks);

    for(quint32 i = 0; i < _blocks.size(); ++i) {
        int linesPerBlock = std::min((qint32)_maxLines, totalLines);
        _blocks[i] = new GridBlockInternal(linesPerBlock, _size.xsize());
        _blockSizes[i] = linesPerBlock * _size.xsize();
        _blockOffsets[i] = i == 0 ? 0 : _blockOffsets[i-1] +  _blockSizes[i];
        totalLines -= _maxLines;
        if ( totalLines <= 0) // to next band
            totalLines = _size.ysize();
    }
    _offsets.resize(_maxLines);
    for(quint32 y=0; y < _maxLines; ++y) {
        _offsets[y].resize(_size.xsize());
        for(quint32 x=0; x < _size.xsize(); ++x) {
            quint64 linearPos = y * size().xsize() + x;
            _offsets[y][x] = linearPos;
        }
    }
    return true;
}

int Grid::numberOfBlocks() {
    double rblocks = (double)_size.ysize() / _maxLines;
    int nblocks = (int)rblocks;
    double rest = rblocks - nblocks;
    if ( rest >= (1.0 / ( _maxLines + 1))) {
        nblocks++;
    }
    return nblocks * _size.zsize();
}

inline bool Grid::update(quint32 block, bool creation) {
    Locker lock(_mutex);
    if ( block >= _blocks.size() )
        return false;
    if ( !_blocks[block]->isLoaded()) {
        if(!_blocks[block]->load())
            return false;
    }
    if ( creation || _cache.size() == 0) { // at create time we want to preserver the original order in memory

        if ( block > _inMemoryIndex )
            _blocks[_cache.back()]->unload();
        _cache.push_back(block);
    }
    else if ( _cache.front() != block) {
        int index = _cache.indexOf(block);
        if (index >=0) {
            _cache.removeOne(index);
        }
        _cache.push_front(block);
        _cacheHead = block; // for efficiency, no lookup what the head is
        if ( index > (int)_inMemoryIndex) {
            return _blocks[_cache[_inMemoryIndex]]->unload();
        }

    }
    return true;
}

void Grid::unload() {
    Locker lock(_mutex);
    _cache.clear();
    for(GridBlockInternal *block : _blocks) {
        block->unload();
    }
    _inMemoryIndex = 0;
}

<|endoftext|>


<commit_before>/*
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "AllocatedSocketAddress.hxx"
#include "address_quark.h"
#include "util/Error.hxx"
#include "util/Domain.hxx"

#include <socket/resolver.h>

#include <glib.h>

#include <assert.h>
#include <sys/un.h>
#include <netdb.h>
#include <string.h>

static constexpr Domain resolver_domain("resolver");

AllocatedSocketAddress::AllocatedSocketAddress(SocketAddress _address)
    :AllocatedSocketAddress()
{
    assert(!_address.IsNull());

    SetSize(_address.GetSize());
    memcpy(address, _address.GetAddress(), size);
}

void
AllocatedSocketAddress::SetSize(size_t new_size)
{
    if (size == new_size)
        return;

    free(address);
    size = new_size;
    address = (struct sockaddr *)malloc(size);
}

void
AllocatedSocketAddress::SetLocal(const char *path)
{
    const bool is_abstract = *path == '@';

    /* sun_path must be null-terminated unless it's an abstract
       socket */
    const size_t path_length = strlen(path) + !is_abstract;

    struct sockaddr_un *sun;
    SetSize(sizeof(*sun) - sizeof(sun->sun_path) + path_length);
    sun = (struct sockaddr_un *)address;
    sun->sun_family = AF_UNIX;
    memcpy(sun->sun_path, path, path_length);

    if (is_abstract)
        sun->sun_path[0] = 0;
}

bool
AllocatedSocketAddress::Parse(const char *p, int default_port,
                              bool passive, Error &error)
{
    if (*p == '/') {
        SetLocal(p);
        return true;
    }

    if (*p == '@') {
#ifdef __linux
        /* abstract unix domain socket */

        SetLocal(p);
        return true;
#else
        /* Linux specific feature */
        error.Set(resolver_domain, "Abstract sockets supported only on Linux");
        return false;
#endif
    }

    static const struct addrinfo hints = {
        .ai_flags = AI_NUMERICHOST,
        .ai_family = AF_UNSPEC,
        .ai_socktype = SOCK_STREAM,
    };
    static const struct addrinfo passive_hints = {
        .ai_flags = AI_NUMERICHOST|AI_PASSIVE,
        .ai_family = AF_UNSPEC,
        .ai_socktype = SOCK_STREAM,
    };

    struct addrinfo *ai;
    int result = socket_resolve_host_port(p, default_port,
                                          passive ? &passive_hints : &hints,
                                          &ai);
    if (result != 0) {
        error.Format(resolver_domain, result,
                     "Failed to resolve '%s': %s",
                     p, gai_strerror(result));
        return false;
    }

    SetSize(ai->ai_addrlen);
    memcpy(address, ai->ai_addr, size);

    freeaddrinfo(ai);

    return true;
}
<commit_msg>net/AllocatedSocketAddress: use netdb_domain<commit_after>/*
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "AllocatedSocketAddress.hxx"
#include "Error.hxx"
#include "address_quark.h"
#include "util/Error.hxx"
#include "util/Domain.hxx"

#include <socket/resolver.h>

#include <glib.h>

#include <assert.h>
#include <sys/un.h>
#include <netdb.h>
#include <string.h>

static constexpr Domain resolver_domain("resolver");

AllocatedSocketAddress::AllocatedSocketAddress(SocketAddress _address)
    :AllocatedSocketAddress()
{
    assert(!_address.IsNull());

    SetSize(_address.GetSize());
    memcpy(address, _address.GetAddress(), size);
}

void
AllocatedSocketAddress::SetSize(size_t new_size)
{
    if (size == new_size)
        return;

    free(address);
    size = new_size;
    address = (struct sockaddr *)malloc(size);
}

void
AllocatedSocketAddress::SetLocal(const char *path)
{
    const bool is_abstract = *path == '@';

    /* sun_path must be null-terminated unless it's an abstract
       socket */
    const size_t path_length = strlen(path) + !is_abstract;

    struct sockaddr_un *sun;
    SetSize(sizeof(*sun) - sizeof(sun->sun_path) + path_length);
    sun = (struct sockaddr_un *)address;
    sun->sun_family = AF_UNIX;
    memcpy(sun->sun_path, path, path_length);

    if (is_abstract)
        sun->sun_path[0] = 0;
}

bool
AllocatedSocketAddress::Parse(const char *p, int default_port,
                              bool passive, Error &error)
{
    if (*p == '/') {
        SetLocal(p);
        return true;
    }

    if (*p == '@') {
#ifdef __linux
        /* abstract unix domain socket */

        SetLocal(p);
        return true;
#else
        /* Linux specific feature */
        error.Set(resolver_domain, "Abstract sockets supported only on Linux");
        return false;
#endif
    }

    static const struct addrinfo hints = {
        .ai_flags = AI_NUMERICHOST,
        .ai_family = AF_UNSPEC,
        .ai_socktype = SOCK_STREAM,
    };
    static const struct addrinfo passive_hints = {
        .ai_flags = AI_NUMERICHOST|AI_PASSIVE,
        .ai_family = AF_UNSPEC,
        .ai_socktype = SOCK_STREAM,
    };

    struct addrinfo *ai;
    int result = socket_resolve_host_port(p, default_port,
                                          passive ? &passive_hints : &hints,
                                          &ai);
    if (result != 0) {
        error.Format(netdb_domain, result,
                     "Failed to resolve '%s': %s",
                     p, gai_strerror(result));
        return false;
    }

    SetSize(ai->ai_addrlen);
    memcpy(address, ai->ai_addr, size);

    freeaddrinfo(ai);

    return true;
}
<|endoftext|>