<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it 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.
**
****************************************************************************/

#include "mcommonpixmaps.h"
#include "mthemedaemon.h"
#include "mdebug.h"
#include <QFile>
#include <QDir>

using namespace M::MThemeDaemonProtocol;

#define VERSION(major, minor) ((major << 16) | minor)
const unsigned int PRELOAD_FILE_VERSION = VERSION(0, 1);

MCommonPixmaps::MCommonPixmaps(MThemeDaemon *daemon) :
    minRequestsForCache(0),
    daemon(daemon)
{
    connect(&cpuMonitor, SIGNAL(newCpuFrameAvailable()), SLOT(loadOne()));
    connect(this, SIGNAL(mostUsedPixmapsChanged(M::MThemeDaemonProtocol::MostUsedPixmaps)), SLOT(considerSaving()));
}

MCommonPixmaps::~MCommonPixmaps()
{
    // please call clear before destroying this object
    Q_ASSERT(mostUsedPixmaps.count() == 0);
}

void MCommonPixmaps::clear()
{
    // release all most used pixmaps
    foreach(const PixmapIdentifier & id, mostUsedPixmaps) {
        if (toLoadList.contains(id))
            continue;

        ImageResource *resource = daemon->findImageResource(id.imageId);
        resource->releasePixmap(id.size);
    }

    cpuMonitor.stop();
    mostUsedPixmaps.clear();
    toLoadList.clear();
    requestCounts.clear();
    minRequestsForCache = 0;
}

void MCommonPixmaps::load()
{
    // clear the old ones.
    clear();

    if (!QFile::exists(cacheFilename())) {
        return;
    }
    QFile file(cacheFilename());
    if (!file.open(QIODevice::ReadOnly)) {
        mWarning("MCommonPixmaps") << "Could not load most used pixmaps from" << cacheFilename();
        return;
    }

    QDataStream stream(&file);

    unsigned int version;
    stream >> version;
    if (version != PRELOAD_FILE_VERSION)
        return;

    while (file.bytesAvailable()) {
        QString imageId;
        QSize size;
        quint32 requestCount;
        bool isMostUsed;
        stream >> imageId >> size >> requestCount >> isMostUsed;

        PixmapIdentifier id(imageId, size);
        requestCounts.insert(id, requestCount);
        if (isMostUsed) {
            toLoadList.insert(PixmapIdentifier(imageId, size));
            mostUsedPixmaps.insert(PixmapIdentifier(imageId, size));
        }
    }

    if (!toLoadList.isEmpty()) {
        cpuMonitor.start(2000);
    }

    file.close();
}

void MCommonPixmaps::save() const
{
    QFile file(cacheFilename());
    if (!file.open(QIODevice::WriteOnly)) {
        mWarning("MCommonPixmaps") << "Could not save most used pixmaps to" << cacheFilename();
        return;
    }

    QDataStream stream(&file);
    stream << PRELOAD_FILE_VERSION;

    QHash<PixmapIdentifier, quint32>::const_iterator i = requestCounts.begin();

    for (; i != requestCounts.end(); ++i) {
        const PixmapIdentifier& id = i.key();

        bool isMostUsed = mostUsedPixmaps.contains(id);
        stream << id.imageId << id.size << i.value() << isMostUsed;
    }

    file.close();
}

void MCommonPixmaps::loadOne()
{
    // stop the timer, so we can adjust the frequency depending on the usage
    cpuMonitor.stop();

    if (0 <= cpuMonitor.usage() || cpuMonitor.usage() < 10) {
        //check if there really is something to load
        if (!toLoadList.isEmpty()) {
            PixmapIdentifier id = *toLoadList.begin();
            toLoadList.erase(toLoadList.begin());

            ImageResource *resource = daemon->findImageResource(id.imageId);
            if (resource) {
                resource->fetchPixmap(id.size);
            } else {
                mWarning("MCommonPixmaps") << QString("Themedaemon could not find resource %1 while loading most used pixmaps. Removing from list.").arg(id.imageId);
                requestCounts.remove(id);
                mostUsedPixmaps.remove(id);
            }

            if (!toLoadList.isEmpty()) {
                // there's still items in the list, so start the timer with small delay
                cpuMonitor.start(250);
            } else {
                // all common pixmaps loaded - notify clients
                MostUsedPixmaps mostUsed;
                mostUsed.addedHandles = mostUsedPixmapHandles();
                emit mostUsedPixmapsChanged(mostUsed);
            }
        }
    } else {
        // the cpu usage was too high, so start start the timer with longer delay
        cpuMonitor.start(2000);
    }
}

void MCommonPixmaps::increaseRequestCount(const M::MThemeDaemonProtocol::PixmapIdentifier &id, ImageResource *resource)
{
    QHash<PixmapIdentifier, quint32>::iterator requestCount = requestCounts.find(id);
    if (requestCount == requestCounts.end()) {
        requestCount = requestCounts.insert(id, 0);
    }
    ++requestCount.value();

    // does this pixmap has higher request count value than the current minimum for cache?
    if (requestCount.value() > minRequestsForCache && !mostUsedPixmaps.contains(id)) {

        // this pixmap might end up to mostUsedPixmaps list

        // check if there's still room for this pixmap
        if (mostUsedPixmaps.count() < MCommonPixmaps::CacheSize) {
            // yep, just add this pixmap and return
            Qt::HANDLE handle = resource->fetchPixmap(id.size);
            mostUsedPixmaps.insert(id);

            MostUsedPixmaps packet;
            packet.addedHandles.append(PixmapHandle(id, handle));
            if (toLoadList.isEmpty()) {
                emit mostUsedPixmapsChanged(packet);
            }
            return;
        }

        // there was no room, so we'll check if we can make it
        QSet<PixmapIdentifier>::iterator i = mostUsedPixmaps.begin();
        QSet<PixmapIdentifier>::iterator leastUsed = i;
        quint32 leastUsedRequests = requestCounts[*leastUsed];
        quint32 secondlyLeastUsedRequests = leastUsedRequests;
        ++i;

        // find the least used pixmap from most used list
        for (; i != mostUsedPixmaps.end(); ++i) {
            const PixmapIdentifier &curId = *i;
            quint32 count = requestCounts[curId];
            if (count < leastUsedRequests) {
                secondlyLeastUsedRequests = leastUsedRequests;
                leastUsedRequests = count;
                leastUsed = i;
            }
        }

        // if the least used is still above the current, we'll just update the limit
        if (leastUsedRequests >= requestCount.value()) {
            minRequestsForCache = leastUsedRequests;
            return;
        }

        // otherwise we have a new pixmap for the list

        // update the limit, there may be duplicate request counts in the most used list
        minRequestsForCache = (secondlyLeastUsedRequests > requestCount.value()) ? requestCount.value() : secondlyLeastUsedRequests;

        // allocate one pixmap for the list
        Qt::HANDLE handle = resource->fetchPixmap(id.size);
        MostUsedPixmaps packet;
        packet.addedHandles.append(PixmapHandle(id, handle));

        // release the old one from the list
        if (!toLoadList.remove(*leastUsed)) {
            packet.removedIdentifiers.append(id);
        }
        if (toLoadList.isEmpty()) {
            emit mostUsedPixmapsChanged(packet);
        }

        mostUsedPixmaps.remove(*leastUsed);
        mostUsedPixmaps.insert(id);
    }
}

void MCommonPixmaps::reload(const PixmapIdentifier &id, ImageResource *oldResource)
{
    if (toLoadList.contains(id) || !mostUsedPixmaps.contains(id)) {
        // no need to do anything
        return;
    }

    oldResource->releasePixmap(id.size);
    toLoadList.insert(id);
}

QList<M::MThemeDaemonProtocol::PixmapHandle> MCommonPixmaps::mostUsedPixmapHandles()
{
    if (!toLoadList.isEmpty()) {
        // not all pixmaps loaded/valid - return empty list
        return QList<M::MThemeDaemonProtocol::PixmapHandle>();
    }

    // we could also save the handles earlier but it is cheap to do the query
    QList<PixmapHandle> pixmapHandles;
    foreach(const M::MThemeDaemonProtocol::PixmapIdentifier& id, mostUsedPixmaps) {
        Qt::HANDLE handle = daemon->findImageResource(id.imageId)->pixmapHandle(id.size);
        pixmapHandles.append(M::MThemeDaemonProtocol::PixmapHandle(id, handle));
    }

    return pixmapHandles;
}

QString MCommonPixmaps::cacheFilename() const
{
    return daemon->systemThemeCacheDirectory() + QDir::separator() + daemon->currentTheme() + QDir::separator() + QLatin1String("preload.list");
}

void MCommonPixmaps::considerSaving()
{
    // we do not allow more than one update in 10 seconds
    const int delay = 10000;
    if (!timerSinceLastSave.isValid() || timerSinceLastSave.hasExpired(delay)) {
        save();
        timerSinceLastSave.start();
    }
}
<commit_msg>Changes: make valgrind happy<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it 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.
**
****************************************************************************/

#include "mcommonpixmaps.h"
#include "mthemedaemon.h"
#include "mdebug.h"
#include <QFile>
#include <QDir>

using namespace M::MThemeDaemonProtocol;

#define VERSION(major, minor) ((major << 16) | minor)
const unsigned int PRELOAD_FILE_VERSION = VERSION(0, 1);

MCommonPixmaps::MCommonPixmaps(MThemeDaemon *daemon) :
    minRequestsForCache(0),
    daemon(daemon)
{
    connect(&cpuMonitor, SIGNAL(newCpuFrameAvailable()), SLOT(loadOne()));
    connect(this, SIGNAL(mostUsedPixmapsChanged(M::MThemeDaemonProtocol::MostUsedPixmaps)), SLOT(considerSaving()));
    timerSinceLastSave.invalidate();
}

MCommonPixmaps::~MCommonPixmaps()
{
    // please call clear before destroying this object
    Q_ASSERT(mostUsedPixmaps.count() == 0);
}

void MCommonPixmaps::clear()
{
    // release all most used pixmaps
    foreach(const PixmapIdentifier & id, mostUsedPixmaps) {
        if (toLoadList.contains(id))
            continue;

        ImageResource *resource = daemon->findImageResource(id.imageId);
        resource->releasePixmap(id.size);
    }

    cpuMonitor.stop();
    mostUsedPixmaps.clear();
    toLoadList.clear();
    requestCounts.clear();
    minRequestsForCache = 0;
}

void MCommonPixmaps::load()
{
    // clear the old ones.
    clear();

    if (!QFile::exists(cacheFilename())) {
        return;
    }
    QFile file(cacheFilename());
    if (!file.open(QIODevice::ReadOnly)) {
        mWarning("MCommonPixmaps") << "Could not load most used pixmaps from" << cacheFilename();
        return;
    }

    QDataStream stream(&file);

    unsigned int version;
    stream >> version;
    if (version != PRELOAD_FILE_VERSION)
        return;

    while (file.bytesAvailable()) {
        QString imageId;
        QSize size;
        quint32 requestCount;
        bool isMostUsed;
        stream >> imageId >> size >> requestCount >> isMostUsed;

        PixmapIdentifier id(imageId, size);
        requestCounts.insert(id, requestCount);
        if (isMostUsed) {
            toLoadList.insert(PixmapIdentifier(imageId, size));
            mostUsedPixmaps.insert(PixmapIdentifier(imageId, size));
        }
    }

    if (!toLoadList.isEmpty()) {
        cpuMonitor.start(2000);
    }

    file.close();
}

void MCommonPixmaps::save() const
{
    QFile file(cacheFilename());
    if (!file.open(QIODevice::WriteOnly)) {
        mWarning("MCommonPixmaps") << "Could not save most used pixmaps to" << cacheFilename();
        return;
    }

    QDataStream stream(&file);
    stream << PRELOAD_FILE_VERSION;

    QHash<PixmapIdentifier, quint32>::const_iterator i = requestCounts.begin();

    for (; i != requestCounts.end(); ++i) {
        const PixmapIdentifier& id = i.key();

        bool isMostUsed = mostUsedPixmaps.contains(id);
        stream << id.imageId << id.size << i.value() << isMostUsed;
    }

    file.close();
}

void MCommonPixmaps::loadOne()
{
    // stop the timer, so we can adjust the frequency depending on the usage
    cpuMonitor.stop();

    if (0 <= cpuMonitor.usage() || cpuMonitor.usage() < 10) {
        //check if there really is something to load
        if (!toLoadList.isEmpty()) {
            PixmapIdentifier id = *toLoadList.begin();
            toLoadList.erase(toLoadList.begin());

            ImageResource *resource = daemon->findImageResource(id.imageId);
            if (resource) {
                resource->fetchPixmap(id.size);
            } else {
                mWarning("MCommonPixmaps") << QString("Themedaemon could not find resource %1 while loading most used pixmaps. Removing from list.").arg(id.imageId);
                requestCounts.remove(id);
                mostUsedPixmaps.remove(id);
            }

            if (!toLoadList.isEmpty()) {
                // there's still items in the list, so start the timer with small delay
                cpuMonitor.start(250);
            } else {
                // all common pixmaps loaded - notify clients
                MostUsedPixmaps mostUsed;
                mostUsed.addedHandles = mostUsedPixmapHandles();
                emit mostUsedPixmapsChanged(mostUsed);
            }
        }
    } else {
        // the cpu usage was too high, so start start the timer with longer delay
        cpuMonitor.start(2000);
    }
}

void MCommonPixmaps::increaseRequestCount(const M::MThemeDaemonProtocol::PixmapIdentifier &id, ImageResource *resource)
{
    QHash<PixmapIdentifier, quint32>::iterator requestCount = requestCounts.find(id);
    if (requestCount == requestCounts.end()) {
        requestCount = requestCounts.insert(id, 0);
    }
    ++requestCount.value();

    // does this pixmap has higher request count value than the current minimum for cache?
    if (requestCount.value() > minRequestsForCache && !mostUsedPixmaps.contains(id)) {

        // this pixmap might end up to mostUsedPixmaps list

        // check if there's still room for this pixmap
        if (mostUsedPixmaps.count() < MCommonPixmaps::CacheSize) {
            // yep, just add this pixmap and return
            Qt::HANDLE handle = resource->fetchPixmap(id.size);
            mostUsedPixmaps.insert(id);

            MostUsedPixmaps packet;
            packet.addedHandles.append(PixmapHandle(id, handle));
            if (toLoadList.isEmpty()) {
                emit mostUsedPixmapsChanged(packet);
            }
            return;
        }

        // there was no room, so we'll check if we can make it
        QSet<PixmapIdentifier>::iterator i = mostUsedPixmaps.begin();
        QSet<PixmapIdentifier>::iterator leastUsed = i;
        quint32 leastUsedRequests = requestCounts[*leastUsed];
        quint32 secondlyLeastUsedRequests = leastUsedRequests;
        ++i;

        // find the least used pixmap from most used list
        for (; i != mostUsedPixmaps.end(); ++i) {
            const PixmapIdentifier &curId = *i;
            quint32 count = requestCounts[curId];
            if (count < leastUsedRequests) {
                secondlyLeastUsedRequests = leastUsedRequests;
                leastUsedRequests = count;
                leastUsed = i;
            }
        }

        // if the least used is still above the current, we'll just update the limit
        if (leastUsedRequests >= requestCount.value()) {
            minRequestsForCache = leastUsedRequests;
            return;
        }

        // otherwise we have a new pixmap for the list

        // update the limit, there may be duplicate request counts in the most used list
        minRequestsForCache = (secondlyLeastUsedRequests > requestCount.value()) ? requestCount.value() : secondlyLeastUsedRequests;

        // allocate one pixmap for the list
        Qt::HANDLE handle = resource->fetchPixmap(id.size);
        MostUsedPixmaps packet;
        packet.addedHandles.append(PixmapHandle(id, handle));

        // release the old one from the list
        if (!toLoadList.remove(*leastUsed)) {
            packet.removedIdentifiers.append(id);
        }
        if (toLoadList.isEmpty()) {
            emit mostUsedPixmapsChanged(packet);
        }

        mostUsedPixmaps.remove(*leastUsed);
        mostUsedPixmaps.insert(id);
    }
}

void MCommonPixmaps::reload(const PixmapIdentifier &id, ImageResource *oldResource)
{
    if (toLoadList.contains(id) || !mostUsedPixmaps.contains(id)) {
        // no need to do anything
        return;
    }

    oldResource->releasePixmap(id.size);
    toLoadList.insert(id);
}

QList<M::MThemeDaemonProtocol::PixmapHandle> MCommonPixmaps::mostUsedPixmapHandles()
{
    if (!toLoadList.isEmpty()) {
        // not all pixmaps loaded/valid - return empty list
        return QList<M::MThemeDaemonProtocol::PixmapHandle>();
    }

    // we could also save the handles earlier but it is cheap to do the query
    QList<PixmapHandle> pixmapHandles;
    foreach(const M::MThemeDaemonProtocol::PixmapIdentifier& id, mostUsedPixmaps) {
        Qt::HANDLE handle = daemon->findImageResource(id.imageId)->pixmapHandle(id.size);
        pixmapHandles.append(M::MThemeDaemonProtocol::PixmapHandle(id, handle));
    }

    return pixmapHandles;
}

QString MCommonPixmaps::cacheFilename() const
{
    return daemon->systemThemeCacheDirectory() + QDir::separator() + daemon->currentTheme() + QDir::separator() + QLatin1String("preload.list");
}

void MCommonPixmaps::considerSaving()
{
    // we do not allow more than one update in 10 seconds
    const int delay = 10000;
    if (!timerSinceLastSave.isValid() || timerSinceLastSave.hasExpired(delay)) {
        save();
        timerSinceLastSave.start();
    }
}
<|endoftext|>


<commit_before>/*
 * Thread.hpp
 *
 * Copyright (C) 2020 by RStudio, PBC
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#ifndef CORE_THREAD_HPP
#define CORE_THREAD_HPP

#include <queue>

#include <boost/utility.hpp>
#include <boost/function.hpp>

#include <core/BoostErrors.hpp>
#include <core/BoostThread.hpp>
#include <shared_core/Error.hpp>
#include <core/Log.hpp>

#define LOCK_MUTEX(m)                                                          \
   try                                                                         \
   {                                                                           \
      boost::lock_guard<boost::mutex> lock(m);

#define RECURSIVE_LOCK_MUTEX(m)                                                \
   try                                                                         \
   {                                                                           \
      boost::lock_guard<boost::recursive_mutex> lock(m);

#define UNIQUE_LOCK_MUTEX(m, lockvar)                                          \
   try                                                                         \
   {                                                                           \
      boost::unique_lock<boost::mutex> lockvar(m);                             \

#define END_LOCK_MUTEX                                                         \
   }                                                                           \
   catch (const boost::thread_resource_error& e)                               \
   {                                                                           \
      core::Error threadError(boost::thread_error::ec_from_exception(e),       \
                              ERROR_LOCATION);                                 \
      LOG_ERROR(threadError);                                                  \
   }                                                                           \
   CATCH_UNEXPECTED_EXCEPTION

namespace rstudio {
namespace core {
namespace thread {

template <typename T>
class ThreadsafeValue : boost::noncopyable
{
public:
   explicit ThreadsafeValue(const T& value = T()) : value_(value) {}
   virtual ~ThreadsafeValue() {}

   T get()
   {
      LOCK_MUTEX(mutex_)
      {
         return value_;
      }
      END_LOCK_MUTEX

      // keep compiler happy
      return T();
   }

   void set(const T& value)
   {
      LOCK_MUTEX(mutex_)
      {
         value_ = value;
      }
      END_LOCK_MUTEX
   }

private:
   boost::mutex mutex_;
   T value_;
};

template <typename K, typename V>
class ThreadsafeMap : boost::noncopyable
{
public:
   ThreadsafeMap() {}
   virtual ~ThreadsafeMap() {}

   bool contains(const K& key)
   {
      LOCK_MUTEX(mutex_)
      {
         return map_.find(key) != map_.end();
      }
      END_LOCK_MUTEX

      // keep compiler happy
      return false;
   }

   V get(const K& key, const V& defaultValue = V())
   {
      LOCK_MUTEX(mutex_)
      {
         typename std::map<K,V>::const_iterator it = map_.find(key);
         if (it != map_.end())
            return it->second;
         else
            return defaultValue;
      }
      END_LOCK_MUTEX

      // keep compiler happy
      return defaultValue;
   }

   V collect(const K& key)
   {
      LOCK_MUTEX(mutex_)
      {
         typename std::map<K,V>::const_iterator it = map_.find(key);
         if (it != map_.end())
         {
            V val = it->second;
            map_.erase(key);
            return val;
         }
      }
      END_LOCK_MUTEX

      return V();
   }

   void set(const K& key, const V& val)
   {
      LOCK_MUTEX(mutex_)
      {
         map_[key] = val;
      }
      END_LOCK_MUTEX
   }

   void remove(const K& key)
   {
      LOCK_MUTEX(mutex_)
      {
         map_.erase(key);
      }
      END_LOCK_MUTEX
   }

   void clear()
   {
      LOCK_MUTEX(mutex_)
      {
         map_.clear();
      }
      END_LOCK_MUTEX
   }

private:
   boost::mutex mutex_;
   std::map<K,V> map_;
};

template <typename T>
class ThreadsafeQueue : boost::noncopyable
{
public:
   explicit ThreadsafeQueue(bool freeSyncObjects = false)
      :  pMutex_(new boost::mutex()),
         pWaitCondition_(new boost::condition()),
         freeSyncObjects_(freeSyncObjects)
   {
   }

   virtual ~ThreadsafeQueue()
   {
      try
      {
         if (freeSyncObjects_)
         {
            delete pMutex_;
            delete pWaitCondition_;
         }
      }
      catch(...)
      {
      }
   }

   // COPYING: boost::noncopyable

public:

   void enque(const T& val)
   {
      LOCK_MUTEX(*pMutex_)
      {
         // enque
         queue_.push(val);
      }
      END_LOCK_MUTEX

      pWaitCondition_->notify_all();
   }

   bool deque(T* pVal)
   {
      LOCK_MUTEX(*pMutex_)
      {
         if (!queue_.empty())
         {
            // remove it
            *pVal = queue_.front();
            queue_.pop();

            // return true
            return true;
         }
         else
         {
            return false;
         }
      }
      END_LOCK_MUTEX

      // keep compiler happy
      return false;
   }

   bool isEmpty()
   {
      LOCK_MUTEX(*pMutex_)
      {
         return queue_.empty();
      }
      END_LOCK_MUTEX

      // keep compiler happy
      return true;
   }

   bool deque(T* pVal, const boost::posix_time::time_duration& waitDuration)
   {
      // first see if we already have one
      if (deque(pVal))
         return true;

      // now wait the specified interval for one to materialize
      if (wait(waitDuration))
         return deque(pVal);
      else
         return false;
   }

   bool wait(const boost::posix_time::time_duration& waitDuration =
                boost::posix_time::time_duration(boost::posix_time::not_a_date_time))
   {
      using namespace boost;
      try
      {
         unique_lock<mutex> lock(*pMutex_);
         if (waitDuration.is_not_a_date_time())
         {
            pWaitCondition_->wait(lock);
            return true;
         }
         else
         {
            system_time timeoutTime = get_system_time() + waitDuration;
            return pWaitCondition_->timed_wait(lock, timeoutTime);
         }
      }
      catch(const thread_resource_error& e)
      {
         Error waitError(boost::thread_error::ec_from_exception(e), ERROR_LOCATION);
         LOG_ERROR(waitError);
         return false;
      }
   }

private:
   // synchronization objects. heap based so that we can control whether
   // they are destroyed or not (boost has been known to crash if a mutex
   // is being destroyed while it is being waited on so sometimes it is
   // better to simply never delete these objects
   boost::mutex* pMutex_;
   boost::condition* pWaitCondition_;

   // instance data
   const bool freeSyncObjects_;
   std::queue<T> queue_;
};

template <typename T>
class ThreadsafeSet
{
public:
   bool contains(const T& value) const
   {
      LOCK_MUTEX(mutex_)
      {
         return set_.find(value) != set_.end();
      }
      END_LOCK_MUTEX

      // This will only be hit if we had a problem acquiring the lock, which likely means we have bigger problems.
      return false;
   }

   void insert(const T& value)
   {
      LOCK_MUTEX(mutex_)
      {
         set_.insert(value);
      }
      END_LOCK_MUTEX
   }

   void insert(T&& value)
   {
      LOCK_MUTEX(mutex_)
      {
         set_.insert(value);
      }
      END_LOCK_MUTEX
   }

   void remove(const T& value)
   {
      std::set<std::string> test;
      LOCK_MUTEX(mutex_)
      {
         auto itr = set_.find(value);
         if (itr != set_.end())
            set_.erase(value);
      }
      END_LOCK_MUTEX
   }

private:
   // We need to supply the default std::set template argument values because there's a compiler bug pre MSVC 2019 16.6:
   // https://developercommunity.visualstudio.com/content/problem/910615/c2976-during-function-template-argument-deduction.html
   std::set<T, std::less<T>, std::allocator<T> > set_;
   mutable boost::mutex mutex_;
};

void safeLaunchThread(boost::function<void()> threadMain,
                      boost::thread* pThread = nullptr);

} // namespace thread
} // namespace core
} // namespace rstudio

#endif // CORE_THREAD_HPP

<commit_msg>Remove debugging code from Thread.hpp (std::set<std::string> test)<commit_after>/*
 * Thread.hpp
 *
 * Copyright (C) 2020 by RStudio, PBC
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#ifndef CORE_THREAD_HPP
#define CORE_THREAD_HPP

#include <queue>

#include <boost/utility.hpp>
#include <boost/function.hpp>

#include <core/BoostErrors.hpp>
#include <core/BoostThread.hpp>
#include <shared_core/Error.hpp>
#include <core/Log.hpp>

#define LOCK_MUTEX(m)                                                          \
   try                                                                         \
   {                                                                           \
      boost::lock_guard<boost::mutex> lock(m);

#define RECURSIVE_LOCK_MUTEX(m)                                                \
   try                                                                         \
   {                                                                           \
      boost::lock_guard<boost::recursive_mutex> lock(m);

#define UNIQUE_LOCK_MUTEX(m, lockvar)                                          \
   try                                                                         \
   {                                                                           \
      boost::unique_lock<boost::mutex> lockvar(m);                             \

#define END_LOCK_MUTEX                                                         \
   }                                                                           \
   catch (const boost::thread_resource_error& e)                               \
   {                                                                           \
      core::Error threadError(boost::thread_error::ec_from_exception(e),       \
                              ERROR_LOCATION);                                 \
      LOG_ERROR(threadError);                                                  \
   }                                                                           \
   CATCH_UNEXPECTED_EXCEPTION

namespace rstudio {
namespace core {
namespace thread {

template <typename T>
class ThreadsafeValue : boost::noncopyable
{
public:
   explicit ThreadsafeValue(const T& value = T()) : value_(value) {}
   virtual ~ThreadsafeValue() {}

   T get()
   {
      LOCK_MUTEX(mutex_)
      {
         return value_;
      }
      END_LOCK_MUTEX

      // keep compiler happy
      return T();
   }

   void set(const T& value)
   {
      LOCK_MUTEX(mutex_)
      {
         value_ = value;
      }
      END_LOCK_MUTEX
   }

private:
   boost::mutex mutex_;
   T value_;
};

template <typename K, typename V>
class ThreadsafeMap : boost::noncopyable
{
public:
   ThreadsafeMap() {}
   virtual ~ThreadsafeMap() {}

   bool contains(const K& key)
   {
      LOCK_MUTEX(mutex_)
      {
         return map_.find(key) != map_.end();
      }
      END_LOCK_MUTEX

      // keep compiler happy
      return false;
   }

   V get(const K& key, const V& defaultValue = V())
   {
      LOCK_MUTEX(mutex_)
      {
         typename std::map<K,V>::const_iterator it = map_.find(key);
         if (it != map_.end())
            return it->second;
         else
            return defaultValue;
      }
      END_LOCK_MUTEX

      // keep compiler happy
      return defaultValue;
   }

   V collect(const K& key)
   {
      LOCK_MUTEX(mutex_)
      {
         typename std::map<K,V>::const_iterator it = map_.find(key);
         if (it != map_.end())
         {
            V val = it->second;
            map_.erase(key);
            return val;
         }
      }
      END_LOCK_MUTEX

      return V();
   }

   void set(const K& key, const V& val)
   {
      LOCK_MUTEX(mutex_)
      {
         map_[key] = val;
      }
      END_LOCK_MUTEX
   }

   void remove(const K& key)
   {
      LOCK_MUTEX(mutex_)
      {
         map_.erase(key);
      }
      END_LOCK_MUTEX
   }

   void clear()
   {
      LOCK_MUTEX(mutex_)
      {
         map_.clear();
      }
      END_LOCK_MUTEX
   }

private:
   boost::mutex mutex_;
   std::map<K,V> map_;
};

template <typename T>
class ThreadsafeQueue : boost::noncopyable
{
public:
   explicit ThreadsafeQueue(bool freeSyncObjects = false)
      :  pMutex_(new boost::mutex()),
         pWaitCondition_(new boost::condition()),
         freeSyncObjects_(freeSyncObjects)
   {
   }

   virtual ~ThreadsafeQueue()
   {
      try
      {
         if (freeSyncObjects_)
         {
            delete pMutex_;
            delete pWaitCondition_;
         }
      }
      catch(...)
      {
      }
   }

   // COPYING: boost::noncopyable

public:

   void enque(const T& val)
   {
      LOCK_MUTEX(*pMutex_)
      {
         // enque
         queue_.push(val);
      }
      END_LOCK_MUTEX

      pWaitCondition_->notify_all();
   }

   bool deque(T* pVal)
   {
      LOCK_MUTEX(*pMutex_)
      {
         if (!queue_.empty())
         {
            // remove it
            *pVal = queue_.front();
            queue_.pop();

            // return true
            return true;
         }
         else
         {
            return false;
         }
      }
      END_LOCK_MUTEX

      // keep compiler happy
      return false;
   }

   bool isEmpty()
   {
      LOCK_MUTEX(*pMutex_)
      {
         return queue_.empty();
      }
      END_LOCK_MUTEX

      // keep compiler happy
      return true;
   }

   bool deque(T* pVal, const boost::posix_time::time_duration& waitDuration)
   {
      // first see if we already have one
      if (deque(pVal))
         return true;

      // now wait the specified interval for one to materialize
      if (wait(waitDuration))
         return deque(pVal);
      else
         return false;
   }

   bool wait(const boost::posix_time::time_duration& waitDuration =
                boost::posix_time::time_duration(boost::posix_time::not_a_date_time))
   {
      using namespace boost;
      try
      {
         unique_lock<mutex> lock(*pMutex_);
         if (waitDuration.is_not_a_date_time())
         {
            pWaitCondition_->wait(lock);
            return true;
         }
         else
         {
            system_time timeoutTime = get_system_time() + waitDuration;
            return pWaitCondition_->timed_wait(lock, timeoutTime);
         }
      }
      catch(const thread_resource_error& e)
      {
         Error waitError(boost::thread_error::ec_from_exception(e), ERROR_LOCATION);
         LOG_ERROR(waitError);
         return false;
      }
   }

private:
   // synchronization objects. heap based so that we can control whether
   // they are destroyed or not (boost has been known to crash if a mutex
   // is being destroyed while it is being waited on so sometimes it is
   // better to simply never delete these objects
   boost::mutex* pMutex_;
   boost::condition* pWaitCondition_;

   // instance data
   const bool freeSyncObjects_;
   std::queue<T> queue_;
};

template <typename T>
class ThreadsafeSet
{
public:
   bool contains(const T& value) const
   {
      LOCK_MUTEX(mutex_)
      {
         return set_.find(value) != set_.end();
      }
      END_LOCK_MUTEX

      // This will only be hit if we had a problem acquiring the lock, which likely means we have bigger problems.
      return false;
   }

   void insert(const T& value)
   {
      LOCK_MUTEX(mutex_)
      {
         set_.insert(value);
      }
      END_LOCK_MUTEX
   }

   void insert(T&& value)
   {
      LOCK_MUTEX(mutex_)
      {
         set_.insert(value);
      }
      END_LOCK_MUTEX
   }

   void remove(const T& value)
   {
      LOCK_MUTEX(mutex_)
      {
         auto itr = set_.find(value);
         if (itr != set_.end())
            set_.erase(value);
      }
      END_LOCK_MUTEX
   }

private:
   // We need to supply the default std::set template argument values because there's a compiler bug pre MSVC 2019 16.6:
   // https://developercommunity.visualstudio.com/content/problem/910615/c2976-during-function-template-argument-deduction.html
   std::set<T, std::less<T>, std::allocator<T> > set_;
   mutable boost::mutex mutex_;
};

void safeLaunchThread(boost::function<void()> threadMain,
                      boost::thread* pThread = nullptr);

} // namespace thread
} // namespace core
} // namespace rstudio

#endif // CORE_THREAD_HPP

<|endoftext|>


<commit_before>// ROOT6 modifications
#ifdef __CLING__
#include <AliAnalysisManager.h>
#include <AliAODInputHandler.h>
#include <AliDielectronVarCuts.h>

// Tell ROOT where to find AliPhysics headers
R__ADD_INCLUDE_PATH($ALICE_PHYSICS)
#include <PWGDQ/dielectron/macrosLMEE/Config_miweber_LMEE_PbPb_woCutLib.C>

#endif

AliAnalysisTask *AddTask_miweber_LMEE_PbPb_woCutLib(Int_t cutDefinition = 0,
						    TString outputFileName = "AnalysisResult.root",
						    TString directoryBaseName = "miweber_LMEE_PbPb",
						    Bool_t isNano = kFALSE,
						    Bool_t bCutQA = kTRUE,
						    Bool_t useTPCCorr=kFALSE,
						    Bool_t useRotation=kFALSE,
						    Bool_t useMixing=kTRUE,
						    Bool_t noPairing=kFALSE,
						    Bool_t bUsePileUpCutsTPCClusters = kFALSE,
						      Float_t pileUpCutsTPCClustersMin = 0.,
						      Float_t pileUpCutsTPCClustersMax = 0.
						    ){

  //get the current analysis manager
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    Error("AddTask_miweber_LMEE_PbPb_woCutLib", "No analysis manager found.");
    return 0;
  }

  Bool_t bESDANA=kFALSE; //Autodetect via InputHandler

  // ROOT6 modifications
#ifndef __CLING__
  TString configBasePath("$ALICE_PHYSICS/PWGDQ/dielectron/macrosLMEE/");
  TString configFile("Config_miweber_LMEE_PbPb_woCutLib.C");
  TString configFilePath(configBasePath+configFile);

  //load dielectron configuration files
  if (!gROOT->GetListOfGlobalFunctions()->FindObject(configFile.Data()))
    gROOT->LoadMacro(configFilePath.Data());

#endif

  //Do we have an MC handler?
  Bool_t hasMC=(AliAnalysisManager::GetAnalysisManager()->GetMCtruthEventHandler()!=0x0);

  //AOD Usage currently tested with Input handler
  if (mgr->GetInputEventHandler()->IsA()==AliAODInputHandler::Class()){
    ::Info("AddTask_miweber_LMEE_PbPb_woCutLib", "no dedicated AOD configuration");
  }
  else if (mgr->GetInputEventHandler()->IsA()==AliESDInputHandler::Class()){
    ::Info("AddTask_miweber_LMEE_PbPb_woCutLib","switching on ESD specific code");
    bESDANA=kTRUE;
  }

  //create task and add it to the manager
  AliAnalysisTaskMultiDielectron *task=new AliAnalysisTaskMultiDielectron("MultiDiEData_miweber_PbPb_woCutLib");

  // for MC no  need for physics selection and for Nano AODs this has been done already
  if (!hasMC && !isNano) task->UsePhysicsSelection();

  //Add event filter
  Int_t triggerNames = AliVEvent::kINT7;//PbPb Min Bias, can be set also from outside

  // for Nano AODs this has been done already
  if(!isNano){
    task->SelectCollisionCandidates(triggerNames);
    task->SetTriggerMask(triggerNames);
    // task->SetRejectPileup(); // to be done differently (too strong cuts at the moment in dielectron framework)
  }

  // Note: event cuts are identical for all analysis 'cutDefinition's that run together!

  //Add event filter
  task->SetEventFilter( GetEventCuts() );

  // Add the task to the manager
  mgr->AddTask(task);

  //add dielectron analysis with selected cut to the task
  AliDielectron *diel_low = Config_miweber_LMEE_PbPb_woCutLib(cutDefinition,bESDANA,bCutQA,kFALSE,useTPCCorr,useRotation,useMixing,noPairing,hasMC);
  if(diel_low){
    AliDielectronVarCuts *eventplaneCuts = new AliDielectronVarCuts("eventplaneCuts","eventplaneCuts");

    // use event plane cuts only for this cut set
    if(cutDefinition==671){
      eventplaneCuts->AddCut(AliDielectronVarManager::kQnTPCrpH2,-999.,kTRUE); // makes sure that the event has an eventplane
      eventplaneCuts->Print();
      diel_low->GetEventFilter().AddCuts(eventplaneCuts);
    }

    // use pile-up rejection cuts based on TPC clusters/event
    if(bUsePileUpCutsTPCClusters){

      Printf("Using TPC cluster based pile-up cuts with parameter 0 from %f to %f",pileUpCutsTPCClustersMin,pileUpCutsTPCClustersMax);

      TF1* fFitMin = new TF1("fFit","pol4",0,90);
      fFitMin->SetParameters(pileUpCutsTPCClustersMin,-109555,2309.01,-27.2048,0.129126);
      TF1* fFitMax = new TF1("fFit","pol4",0,90);
      fFitMax->SetParameters(pileUpCutsTPCClustersMax,-109555,2309.01,-27.2048,0.129126);

      AliDielectronEventCuts *pileUpCuts = new AliDielectronEventCuts("pileUpCuts","pileUpCuts");
      pileUpCuts->SetMinCorrCutFunction(fFitMin, AliDielectronVarManager::kCentralityNew, AliDielectronVarManager::kNTPCclsEvent);
      pileUpCuts->SetMaxCorrCutFunction(fFitMax, AliDielectronVarManager::kCentralityNew, AliDielectronVarManager::kNTPCclsEvent);

      pileUpCuts->Print();
      diel_low->GetEventFilter().AddCuts(pileUpCuts);
    }

    task->AddDielectron(diel_low);
    printf("successfully added AliDielectron: %s\n",diel_low->GetName());
  }
  else{
    Printf("=======================================");
    Printf("No AliDielectron object loaded -> EXIT ");
    Printf("=======================================");
    return NULL;
  }

  //create output container
  AliAnalysisDataContainer *coutput1 =
    mgr->CreateContainer(Form("%s_tree",directoryBaseName.Data()),
                         TTree::Class(),
                         AliAnalysisManager::kExchangeContainer,
                         outputFileName.Data());

  AliAnalysisDataContainer *cOutputHist1 =
    mgr->CreateContainer(Form("%s_out",directoryBaseName.Data()),
                         TList::Class(),
                         AliAnalysisManager::kOutputContainer,
                         outputFileName.Data());

  AliAnalysisDataContainer *cOutputHist2 =
    mgr->CreateContainer(Form("%s_CF",directoryBaseName.Data()),
                         TList::Class(),
                         AliAnalysisManager::kOutputContainer,
                         outputFileName.Data());
  //                         "miweber_LMEE_PbPb_CF.root");

  AliAnalysisDataContainer *cOutputHist3 =
    mgr->CreateContainer(Form("%s_EventStat",directoryBaseName.Data()),
                         TH1D::Class(),
                         AliAnalysisManager::kOutputContainer,
                         outputFileName.Data());

  mgr->ConnectInput(task,  0, mgr->GetCommonInputContainer());
  if((AliAnalysisDataContainer*)mgr->GetContainers()->FindObject("ZDCEPExchangeContainer"))
    mgr->ConnectInput(task,  1,(AliAnalysisDataContainer*)mgr->GetContainers()->FindObject("ZDCEPExchangeContainer"));
  mgr->ConnectOutput(task, 0, coutput1 );
  mgr->ConnectOutput(task, 1, cOutputHist1);
  mgr->ConnectOutput(task, 2, cOutputHist2);
  mgr->ConnectOutput(task, 3, cOutputHist3);

  return task;
}
<commit_msg>TPC cluster fit for pile-up: pol4 -> pol6<commit_after>// ROOT6 modifications
#ifdef __CLING__
#include <AliAnalysisManager.h>
#include <AliAODInputHandler.h>
#include <AliDielectronVarCuts.h>

// Tell ROOT where to find AliPhysics headers
R__ADD_INCLUDE_PATH($ALICE_PHYSICS)
#include <PWGDQ/dielectron/macrosLMEE/Config_miweber_LMEE_PbPb_woCutLib.C>

#endif

AliAnalysisTask *AddTask_miweber_LMEE_PbPb_woCutLib(Int_t cutDefinition = 0,
						    TString outputFileName = "AnalysisResult.root",
						    TString directoryBaseName = "miweber_LMEE_PbPb",
						    Bool_t isNano = kFALSE,
						    Bool_t bCutQA = kTRUE,
						    Bool_t useTPCCorr=kFALSE,
						    Bool_t useRotation=kFALSE,
						    Bool_t useMixing=kTRUE,
						    Bool_t noPairing=kFALSE,
						    Bool_t bUsePileUpCutsTPCClusters = kFALSE,
						      Float_t pileUpCutsTPCClustersMin = 0.,
						      Float_t pileUpCutsTPCClustersMax = 0.
						    ){

  //get the current analysis manager
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    Error("AddTask_miweber_LMEE_PbPb_woCutLib", "No analysis manager found.");
    return 0;
  }

  Bool_t bESDANA=kFALSE; //Autodetect via InputHandler

  // ROOT6 modifications
#ifndef __CLING__
  TString configBasePath("$ALICE_PHYSICS/PWGDQ/dielectron/macrosLMEE/");
  TString configFile("Config_miweber_LMEE_PbPb_woCutLib.C");
  TString configFilePath(configBasePath+configFile);

  //load dielectron configuration files
  if (!gROOT->GetListOfGlobalFunctions()->FindObject(configFile.Data()))
    gROOT->LoadMacro(configFilePath.Data());

#endif

  //Do we have an MC handler?
  Bool_t hasMC=(AliAnalysisManager::GetAnalysisManager()->GetMCtruthEventHandler()!=0x0);

  //AOD Usage currently tested with Input handler
  if (mgr->GetInputEventHandler()->IsA()==AliAODInputHandler::Class()){
    ::Info("AddTask_miweber_LMEE_PbPb_woCutLib", "no dedicated AOD configuration");
  }
  else if (mgr->GetInputEventHandler()->IsA()==AliESDInputHandler::Class()){
    ::Info("AddTask_miweber_LMEE_PbPb_woCutLib","switching on ESD specific code");
    bESDANA=kTRUE;
  }

  //create task and add it to the manager
  AliAnalysisTaskMultiDielectron *task=new AliAnalysisTaskMultiDielectron("MultiDiEData_miweber_PbPb_woCutLib");

  // for MC no  need for physics selection and for Nano AODs this has been done already
  if (!hasMC && !isNano) task->UsePhysicsSelection();

  //Add event filter
  Int_t triggerNames = AliVEvent::kINT7;//PbPb Min Bias, can be set also from outside

  // for Nano AODs this has been done already
  if(!isNano){
    task->SelectCollisionCandidates(triggerNames);
    task->SetTriggerMask(triggerNames);
    // task->SetRejectPileup(); // to be done differently (too strong cuts at the moment in dielectron framework)
  }

  // Note: event cuts are identical for all analysis 'cutDefinition's that run together!

  //Add event filter
  task->SetEventFilter( GetEventCuts() );

  // Add the task to the manager
  mgr->AddTask(task);

  //add dielectron analysis with selected cut to the task
  AliDielectron *diel_low = Config_miweber_LMEE_PbPb_woCutLib(cutDefinition,bESDANA,bCutQA,kFALSE,useTPCCorr,useRotation,useMixing,noPairing,hasMC);
  if(diel_low){
    AliDielectronVarCuts *eventplaneCuts = new AliDielectronVarCuts("eventplaneCuts","eventplaneCuts");

    // use event plane cuts only for this cut set
    if(cutDefinition==671){
      eventplaneCuts->AddCut(AliDielectronVarManager::kQnTPCrpH2,-999.,kTRUE); // makes sure that the event has an eventplane
      eventplaneCuts->Print();
      diel_low->GetEventFilter().AddCuts(eventplaneCuts);
    }

    // use pile-up rejection cuts based on TPC clusters/event
    if(bUsePileUpCutsTPCClusters){

      Printf("Using TPC cluster based pile-up cuts with parameter 0 from %f to %f",pileUpCutsTPCClustersMin,pileUpCutsTPCClustersMax);

      TF1* fFitMin = new TF1("fFit","pol6",0,90);
      TF1* fFitMax = new TF1("fFit","pol6",0,90);
      fFitMin->SetParameters(pileUpCutsTPCClustersMin,-95678.946999,2152.010478,-50.119000,0.780528,-0.006150,0.000019);
      fFitMax->SetParameters(pileUpCutsTPCClustersMax,-95678.946999,2152.010478,-50.119000,0.780528,-0.006150,0.000019);

      AliDielectronEventCuts *pileUpCuts = new AliDielectronEventCuts("pileUpCuts","pileUpCuts");
      pileUpCuts->SetMinCorrCutFunction(fFitMin, AliDielectronVarManager::kCentralityNew, AliDielectronVarManager::kNTPCclsEvent);
      pileUpCuts->SetMaxCorrCutFunction(fFitMax, AliDielectronVarManager::kCentralityNew, AliDielectronVarManager::kNTPCclsEvent);

      pileUpCuts->Print();
      diel_low->GetEventFilter().AddCuts(pileUpCuts);
    }

    task->AddDielectron(diel_low);
    printf("successfully added AliDielectron: %s\n",diel_low->GetName());
  }
  else{
    Printf("=======================================");
    Printf("No AliDielectron object loaded -> EXIT ");
    Printf("=======================================");
    return NULL;
  }

  //create output container
  AliAnalysisDataContainer *coutput1 =
    mgr->CreateContainer(Form("%s_tree",directoryBaseName.Data()),
                         TTree::Class(),
                         AliAnalysisManager::kExchangeContainer,
                         outputFileName.Data());

  AliAnalysisDataContainer *cOutputHist1 =
    mgr->CreateContainer(Form("%s_out",directoryBaseName.Data()),
                         TList::Class(),
                         AliAnalysisManager::kOutputContainer,
                         outputFileName.Data());

  AliAnalysisDataContainer *cOutputHist2 =
    mgr->CreateContainer(Form("%s_CF",directoryBaseName.Data()),
                         TList::Class(),
                         AliAnalysisManager::kOutputContainer,
                         outputFileName.Data());
  //                         "miweber_LMEE_PbPb_CF.root");

  AliAnalysisDataContainer *cOutputHist3 =
    mgr->CreateContainer(Form("%s_EventStat",directoryBaseName.Data()),
                         TH1D::Class(),
                         AliAnalysisManager::kOutputContainer,
                         outputFileName.Data());

  mgr->ConnectInput(task,  0, mgr->GetCommonInputContainer());
  if((AliAnalysisDataContainer*)mgr->GetContainers()->FindObject("ZDCEPExchangeContainer"))
    mgr->ConnectInput(task,  1,(AliAnalysisDataContainer*)mgr->GetContainers()->FindObject("ZDCEPExchangeContainer"));
  mgr->ConnectOutput(task, 0, coutput1 );
  mgr->ConnectOutput(task, 1, cOutputHist1);
  mgr->ConnectOutput(task, 2, cOutputHist2);
  mgr->ConnectOutput(task, 3, cOutputHist3);

  return task;
}
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2019 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name PX4 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
 * COPYRIGHT OWNER 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.
 *
 ****************************************************************************/

#pragma once

#include <stdint.h>

namespace px4
{

class WorkQueue; // forward declaration

struct wq_config_t {
	const char *name;
	uint16_t stacksize;
	int8_t relative_priority; // relative to max
};

namespace wq_configurations
{
static constexpr wq_config_t rate_ctrl{"wq:rate_ctrl", 1600, 0}; // PX4 inner loop highest priority

static constexpr wq_config_t SPI0{"wq:SPI0", 1900, -1};
static constexpr wq_config_t SPI1{"wq:SPI1", 1900, -2};
static constexpr wq_config_t SPI2{"wq:SPI2", 1900, -3};
static constexpr wq_config_t SPI3{"wq:SPI3", 1900, -4};
static constexpr wq_config_t SPI4{"wq:SPI4", 1900, -5};
static constexpr wq_config_t SPI5{"wq:SPI5", 1900, -6};
static constexpr wq_config_t SPI6{"wq:SPI6", 1900, -7};

static constexpr wq_config_t I2C0{"wq:I2C0", 1400, -8};
static constexpr wq_config_t I2C1{"wq:I2C1", 1400, -9};
static constexpr wq_config_t I2C2{"wq:I2C2", 1400, -10};
static constexpr wq_config_t I2C3{"wq:I2C3", 1400, -11};
static constexpr wq_config_t I2C4{"wq:I2C4", 1400, -12};

static constexpr wq_config_t att_pos_ctrl{"wq:att_pos_ctrl", 6600, -13}; // PX4 att/pos controllers, highest priority after sensors

static constexpr wq_config_t hp_default{"wq:hp_default", 1900, -14};

static constexpr wq_config_t uavcan{"wq:uavcan", 2400, -15};

static constexpr wq_config_t UART0{"wq:UART0", 1400, -16};
static constexpr wq_config_t UART1{"wq:UART1", 1400, -17};
static constexpr wq_config_t UART2{"wq:UART2", 1400, -18};
static constexpr wq_config_t UART3{"wq:UART3", 1400, -19};
static constexpr wq_config_t UART4{"wq:UART4", 1400, -20};
static constexpr wq_config_t UART5{"wq:UART5", 1400, -21};
static constexpr wq_config_t UART6{"wq:UART6", 1400, -22};
static constexpr wq_config_t UART7{"wq:UART7", 1400, -23};
static constexpr wq_config_t UART8{"wq:UART8", 1400, -24};
static constexpr wq_config_t UART_UNKNOWN{"wq:UART_UNKNOWN", 1400, -25};

static constexpr wq_config_t lp_default{"wq:lp_default", 1700, -50};

static constexpr wq_config_t test1{"wq:test1", 800, 0};
static constexpr wq_config_t test2{"wq:test2", 800, 0};

} // namespace wq_configurations

/**
 * Start the work queue manager task.
 */
int WorkQueueManagerStart();

/**
 * Stop the work queue manager task.
 */
int WorkQueueManagerStop();

/**
 * Work queue manager status.
 */
int WorkQueueManagerStatus();

/**
 * Create (or find) a work queue with a particular configuration.
 *
 * @param new_wq		The work queue configuration (see WorkQueueManager.hpp).
 * @return		A pointer to the WorkQueue, or nullptr on failure.
 */
WorkQueue *WorkQueueFindOrCreate(const wq_config_t &new_wq);

/**
 * Map a PX4 driver device id to a work queue (by sensor bus).
 *
 * @param device_id		The PX4 driver's device id.
 * @return		A work queue configuration.
 */
const wq_config_t &device_bus_to_wq(uint32_t device_id);

/**
 * Map a serial device path (eg /dev/ttyS1) to a work queue.
 *
 * @param device_id		The device path.
 * @return		A work queue configuration.
 */
const wq_config_t &serial_port_to_wq(const char *serial);

} // namespace px4
<commit_msg>platforms: prevent stackoverflow for ekf2 sideslip<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2019 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name PX4 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
 * COPYRIGHT OWNER 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.
 *
 ****************************************************************************/

#pragma once

#include <stdint.h>

namespace px4
{

class WorkQueue; // forward declaration

struct wq_config_t {
	const char *name;
	uint16_t stacksize;
	int8_t relative_priority; // relative to max
};

namespace wq_configurations
{
static constexpr wq_config_t rate_ctrl{"wq:rate_ctrl", 1600, 0}; // PX4 inner loop highest priority

static constexpr wq_config_t SPI0{"wq:SPI0", 1900, -1};
static constexpr wq_config_t SPI1{"wq:SPI1", 1900, -2};
static constexpr wq_config_t SPI2{"wq:SPI2", 1900, -3};
static constexpr wq_config_t SPI3{"wq:SPI3", 1900, -4};
static constexpr wq_config_t SPI4{"wq:SPI4", 1900, -5};
static constexpr wq_config_t SPI5{"wq:SPI5", 1900, -6};
static constexpr wq_config_t SPI6{"wq:SPI6", 1900, -7};

static constexpr wq_config_t I2C0{"wq:I2C0", 1400, -8};
static constexpr wq_config_t I2C1{"wq:I2C1", 1400, -9};
static constexpr wq_config_t I2C2{"wq:I2C2", 1400, -10};
static constexpr wq_config_t I2C3{"wq:I2C3", 1400, -11};
static constexpr wq_config_t I2C4{"wq:I2C4", 1400, -12};

// PX4 att/pos controllers, highest priority after sensors.
static constexpr wq_config_t att_pos_ctrl{"wq:att_pos_ctrl", 7200, -13};

static constexpr wq_config_t hp_default{"wq:hp_default", 1900, -14};

static constexpr wq_config_t uavcan{"wq:uavcan", 2400, -15};

static constexpr wq_config_t UART0{"wq:UART0", 1400, -16};
static constexpr wq_config_t UART1{"wq:UART1", 1400, -17};
static constexpr wq_config_t UART2{"wq:UART2", 1400, -18};
static constexpr wq_config_t UART3{"wq:UART3", 1400, -19};
static constexpr wq_config_t UART4{"wq:UART4", 1400, -20};
static constexpr wq_config_t UART5{"wq:UART5", 1400, -21};
static constexpr wq_config_t UART6{"wq:UART6", 1400, -22};
static constexpr wq_config_t UART7{"wq:UART7", 1400, -23};
static constexpr wq_config_t UART8{"wq:UART8", 1400, -24};
static constexpr wq_config_t UART_UNKNOWN{"wq:UART_UNKNOWN", 1400, -25};

static constexpr wq_config_t lp_default{"wq:lp_default", 1700, -50};

static constexpr wq_config_t test1{"wq:test1", 800, 0};
static constexpr wq_config_t test2{"wq:test2", 800, 0};

} // namespace wq_configurations

/**
 * Start the work queue manager task.
 */
int WorkQueueManagerStart();

/**
 * Stop the work queue manager task.
 */
int WorkQueueManagerStop();

/**
 * Work queue manager status.
 */
int WorkQueueManagerStatus();

/**
 * Create (or find) a work queue with a particular configuration.
 *
 * @param new_wq		The work queue configuration (see WorkQueueManager.hpp).
 * @return		A pointer to the WorkQueue, or nullptr on failure.
 */
WorkQueue *WorkQueueFindOrCreate(const wq_config_t &new_wq);

/**
 * Map a PX4 driver device id to a work queue (by sensor bus).
 *
 * @param device_id		The PX4 driver's device id.
 * @return		A work queue configuration.
 */
const wq_config_t &device_bus_to_wq(uint32_t device_id);

/**
 * Map a serial device path (eg /dev/ttyS1) to a work queue.
 *
 * @param device_id		The device path.
 * @return		A work queue configuration.
 */
const wq_config_t &serial_port_to_wq(const char *serial);

} // namespace px4
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2020 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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 "file_enotdir.hxx"
#include "Request.hxx"
#include "translation/Response.hxx"
#include "file_address.hxx"
#include "cgi/Address.hxx"
#include "lhttp_address.hxx"
#include "http/IncomingRequest.hxx"
#include "pool/pool.hxx"
#include "io/StatAt.hxx"
#include "AllocatorPtr.hxx"

#include <assert.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>

gcc_pure
static bool
IsEnotdir(const char *base, const char *path) noexcept
{
	struct statx st;
	return !StatAt(base, path, AT_STATX_DONT_SYNC, STATX_TYPE, &st) &&
		errno == ENOTDIR;
}

gcc_pure
static const char *
get_file_path(const TranslateResponse &response)
{
	if (response.test_path != nullptr)
		return response.test_path;

	const auto &address = response.address;
	switch (address.type) {
	case ResourceAddress::Type::NONE:
	case ResourceAddress::Type::HTTP:
	case ResourceAddress::Type::PIPE:
	case ResourceAddress::Type::NFS:
		return nullptr;

	case ResourceAddress::Type::CGI:
	case ResourceAddress::Type::FASTCGI:
	case ResourceAddress::Type::WAS:
		return address.GetCgi().path;

	case ResourceAddress::Type::LHTTP:
		return address.GetLhttp().path;

	case ResourceAddress::Type::LOCAL:
		return address.GetFile().path;

		// TODO: implement NFS
	}

	assert(false);
	gcc_unreachable();
}

gcc_pure
static const char *
get_file_base(const TranslateResponse &response) noexcept
{
	if (response.test_path != nullptr)
		return nullptr;

	const auto &address = response.address;
	switch (address.type) {
	case ResourceAddress::Type::NONE:
	case ResourceAddress::Type::HTTP:
	case ResourceAddress::Type::PIPE:
	case ResourceAddress::Type::NFS:
	case ResourceAddress::Type::CGI:
	case ResourceAddress::Type::FASTCGI:
	case ResourceAddress::Type::WAS:
	case ResourceAddress::Type::LHTTP:
		return nullptr;

	case ResourceAddress::Type::LOCAL:
		return address.GetFile().base;
	}

	assert(false);
	gcc_unreachable();
}

static bool
submit_enotdir(Request &request, const TranslateResponse &response)
{
	request.translate.request.enotdir = response.enotdir;

	const char *const uri = request.request.uri;
	if (request.translate.enotdir_uri == nullptr) {
		request.translate.request.uri = request.translate.enotdir_uri =
			p_strdup(&request.pool, uri);
		request.translate.enotdir_path_info = uri + strlen(uri);
	}

	const char *slash = (const char *)
		memrchr(uri, '/', request.translate.enotdir_path_info - uri);
	if (slash == nullptr || slash == uri)
		return true;

	request.translate.enotdir_uri[slash - uri] = 0;
	request.translate.enotdir_path_info = slash;

	request.SubmitTranslateRequest();
	return false;
}

bool
check_file_enotdir(Request &request,
		   const TranslateResponse &response)
{
	assert(!response.enotdir.IsNull());

	const char *path = get_file_path(response);
	if (path == nullptr) {
		request.LogDispatchError(HTTP_STATUS_BAD_GATEWAY,
					 "Resource address not compatible with ENOTDIR",
					 1);
		return false;
	}

	if (IsEnotdir(get_file_base(response), path))
		return submit_enotdir(request, response);

	return true;
}

void
apply_file_enotdir(Request &request)
{
	if (request.translate.enotdir_path_info != nullptr) {
		/* append the path_info to the resource address */

		auto address =
			request.translate.address.Apply(request.pool,
							request.translate.enotdir_path_info);
		if (address.IsDefined())
			request.translate.address = {ShallowCopy(), address};
	}
}
<commit_msg>bp/file_enotdir: use move operator instead of ShallowCopy<commit_after>/*
 * Copyright 2007-2020 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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 "file_enotdir.hxx"
#include "Request.hxx"
#include "translation/Response.hxx"
#include "file_address.hxx"
#include "cgi/Address.hxx"
#include "lhttp_address.hxx"
#include "http/IncomingRequest.hxx"
#include "pool/pool.hxx"
#include "io/StatAt.hxx"
#include "AllocatorPtr.hxx"

#include <assert.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>

gcc_pure
static bool
IsEnotdir(const char *base, const char *path) noexcept
{
	struct statx st;
	return !StatAt(base, path, AT_STATX_DONT_SYNC, STATX_TYPE, &st) &&
		errno == ENOTDIR;
}

gcc_pure
static const char *
get_file_path(const TranslateResponse &response)
{
	if (response.test_path != nullptr)
		return response.test_path;

	const auto &address = response.address;
	switch (address.type) {
	case ResourceAddress::Type::NONE:
	case ResourceAddress::Type::HTTP:
	case ResourceAddress::Type::PIPE:
	case ResourceAddress::Type::NFS:
		return nullptr;

	case ResourceAddress::Type::CGI:
	case ResourceAddress::Type::FASTCGI:
	case ResourceAddress::Type::WAS:
		return address.GetCgi().path;

	case ResourceAddress::Type::LHTTP:
		return address.GetLhttp().path;

	case ResourceAddress::Type::LOCAL:
		return address.GetFile().path;

		// TODO: implement NFS
	}

	assert(false);
	gcc_unreachable();
}

gcc_pure
static const char *
get_file_base(const TranslateResponse &response) noexcept
{
	if (response.test_path != nullptr)
		return nullptr;

	const auto &address = response.address;
	switch (address.type) {
	case ResourceAddress::Type::NONE:
	case ResourceAddress::Type::HTTP:
	case ResourceAddress::Type::PIPE:
	case ResourceAddress::Type::NFS:
	case ResourceAddress::Type::CGI:
	case ResourceAddress::Type::FASTCGI:
	case ResourceAddress::Type::WAS:
	case ResourceAddress::Type::LHTTP:
		return nullptr;

	case ResourceAddress::Type::LOCAL:
		return address.GetFile().base;
	}

	assert(false);
	gcc_unreachable();
}

static bool
submit_enotdir(Request &request, const TranslateResponse &response)
{
	request.translate.request.enotdir = response.enotdir;

	const char *const uri = request.request.uri;
	if (request.translate.enotdir_uri == nullptr) {
		request.translate.request.uri = request.translate.enotdir_uri =
			p_strdup(&request.pool, uri);
		request.translate.enotdir_path_info = uri + strlen(uri);
	}

	const char *slash = (const char *)
		memrchr(uri, '/', request.translate.enotdir_path_info - uri);
	if (slash == nullptr || slash == uri)
		return true;

	request.translate.enotdir_uri[slash - uri] = 0;
	request.translate.enotdir_path_info = slash;

	request.SubmitTranslateRequest();
	return false;
}

bool
check_file_enotdir(Request &request,
		   const TranslateResponse &response)
{
	assert(!response.enotdir.IsNull());

	const char *path = get_file_path(response);
	if (path == nullptr) {
		request.LogDispatchError(HTTP_STATUS_BAD_GATEWAY,
					 "Resource address not compatible with ENOTDIR",
					 1);
		return false;
	}

	if (IsEnotdir(get_file_base(response), path))
		return submit_enotdir(request, response);

	return true;
}

void
apply_file_enotdir(Request &request)
{
	if (request.translate.enotdir_path_info != nullptr) {
		/* append the path_info to the resource address */

		auto address =
			request.translate.address.Apply(request.pool,
							request.translate.enotdir_path_info);
		if (address.IsDefined())
			request.translate.address = std::move(address);
	}
}
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifdef _MSC_VER
#pragma warning( 4: 4786)
#endif

#include <stdio.h>
#include <iostream>
#include <map>
#include <string>

#include "BZAdminClient.h"
#include "BZAdminUI.h"
#include "OptionParser.h"
#include "UIMap.h"

// causes persistent rebuilding to obtain build versioning
#include "version.h"

int debugLevel = 0;

#ifdef _WIN32
void Player::setDeadReckoning()
{
}
#endif
/** @file
    This is the main file for bzadmin, the bzflag text client.
*/

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

#ifdef _WIN32
  // startup winsock
  {
    static const int major = 2, minor = 2;
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(major, minor), &wsaData)) {
      return 1;
    }
    if (LOBYTE(wsaData.wVersion) != major ||
	HIBYTE(wsaData.wVersion) != minor) {
      WSACleanup();
      return 1;
    }
  }
#endif
  // command line options
  std::string uiName("curses");
  std::vector<std::string> visibleMsgs;
  std::vector<std::string> invisibleMsgs;

  // no curses, use stdboth as default instead
  const UIMap& interfaces = UIMap::instance();
  if (interfaces.find("curses") == interfaces.end())
    uiName = "stdboth";

  // build a usage string with all interfaces
  UIMap::const_iterator uiIter;
  std::string uiUsage;
  for (uiIter = interfaces.begin(); uiIter != interfaces.end(); ++uiIter)
    uiUsage += uiIter->first + '|';
  uiUsage = std::string("[-ui ") + uiUsage.substr(0, uiUsage.size() - 1) + ']';

  // register and parse command line arguments
  OptionParser op(std::string("bzadmin ") + getAppVersion(),
		  "CALLSIGN@HOST[:PORT] [COMMAND] [COMMAND] ...");
  const std::string uiOption("ui");
  const std::string uiMsg = "choose a user interface";
  op.registerVariable(uiOption, uiName, uiUsage, uiMsg);
  op.registerVector("show", visibleMsgs, "[-show msgtype{,msgtype}*]",
		      "tell bzadmin to show these message types");
  op.registerVector("hide", invisibleMsgs, "[-hide msgtype{,msgtype}*]",
		      "tell bzadmin not to show these message types");
  if (!op.parse(argc, argv))
    return 1;

  // check that we have callsign and host in the right format and extract them
  int atPos;
  std::string name = "", host = "";
  if (!(op.getParameters().size() > 0 &&
	(atPos = op.getParameters()[0].find('@')) > 0)) {
    // input callsign and host interactively
    std::cout << "No callsign@host specified.  Please input them" << std::endl;
    std::cout << "Callsign: ";
    std::cin >> name;
    if (name.size() <= 1) {
      std::cerr << "You must specify a callsign.  Exiting." << std::endl;
      return 1;
    }
    std::cout << "Server to connect to: ";
    std::cin >> host;
    if (host.size() <= 1) {
      std::cerr << "You must specify a host name to connect to.  Exiting." << std::endl;
      return 1;
    }
  } else { // callsign/host on command line
    name = op.getParameters()[0].substr(0, atPos);
    host = op.getParameters()[0].substr(atPos + 1);
  }

  int port = ServerPort;
  int cPos = host.find(':');
  if (cPos != -1) {
    port = atoi(host.substr(cPos + 1).c_str());
    host = host.substr(0, cPos);
  }

  // check that the ui is valid
  uiIter = UIMap::instance().find(uiName);
  if (uiIter == UIMap::instance().end()) {
    std::cerr<<"There is no interface called \""<<uiName<<"\"."<<std::endl;
    return 1;
  }

  // try to connect
  BZAdminClient client(name, host, port);
  if (!client.isValid())
    return 1;
  unsigned int i;
  for (i = 0; i < visibleMsgs.size(); ++i)
    client.showMessageType(visibleMsgs[i]);
  for (i = 0; i < invisibleMsgs.size(); ++i)
    client.ignoreMessageType(invisibleMsgs[i]);

  // if we got commands as arguments, send them and exit
  if (op.getParameters().size() > 1) {
    for (unsigned int i = 1; i < op.getParameters().size(); ++i)
      client.sendMessage(op.getParameters()[i], AllPlayers);
    client.waitForServer();
    return 0;
  }

  // create UI and run the main loop
  BZAdminUI*  ui = uiIter->second(client);
  client.setUI(ui);
  client.runLoop();
  delete ui;

  return 0;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>don't quit bzadmin automatically if there are commands as arguments<commit_after>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifdef _MSC_VER
#pragma warning( 4: 4786)
#endif

#include <stdio.h>
#include <iostream>
#include <map>
#include <string>

#include "BZAdminClient.h"
#include "BZAdminUI.h"
#include "OptionParser.h"
#include "UIMap.h"

// causes persistent rebuilding to obtain build versioning
#include "version.h"

int debugLevel = 0;

#ifdef _WIN32
void Player::setDeadReckoning()
{
}
#endif
/** @file
    This is the main file for bzadmin, the bzflag text client.
*/

int main(int argc, char** argv) {
  bool earlyQuit = false;

  // FIXME - build this into OptionParser (VariableSimple parser?)
  if ((argc > 1) && (strcmp (argv[1], "-q") == 0)) {
    earlyQuit = true;
    argv[1] = argv[0]; // eat the option
    argv++;
    argc--;
  }

#ifdef _WIN32
  // startup winsock
  {
    static const int major = 2, minor = 2;
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(major, minor), &wsaData)) {
      return 1;
    }
    if (LOBYTE(wsaData.wVersion) != major ||
	HIBYTE(wsaData.wVersion) != minor) {
      WSACleanup();
      return 1;
    }
  }
#endif
  // command line options
  std::string uiName("curses");
  std::vector<std::string> visibleMsgs;
  std::vector<std::string> invisibleMsgs;

  // no curses, use stdboth as default instead
  const UIMap& interfaces = UIMap::instance();
  if (interfaces.find("curses") == interfaces.end())
    uiName = "stdboth";

  // build a usage string with all interfaces
  UIMap::const_iterator uiIter;
  std::string uiUsage;
  for (uiIter = interfaces.begin(); uiIter != interfaces.end(); ++uiIter)
    uiUsage += uiIter->first + '|';
  uiUsage = std::string("[-ui ") + uiUsage.substr(0, uiUsage.size() - 1) + ']';

  // register and parse command line arguments
  OptionParser op(std::string("bzadmin ") + getAppVersion(),
		  "CALLSIGN@HOST[:PORT] [COMMAND] [COMMAND] ...");
  const std::string uiOption("ui");
  const std::string uiMsg = "choose a user interface";
  op.registerVariable(uiOption, uiName, uiUsage, uiMsg);
  op.registerVector("show", visibleMsgs, "[-show msgtype{,msgtype}*]",
		      "tell bzadmin to show these message types");
  op.registerVector("hide", invisibleMsgs, "[-hide msgtype{,msgtype}*]",
		      "tell bzadmin not to show these message types");
  if (!op.parse(argc, argv))
    return 1;

  // check that we have callsign and host in the right format and extract them
  int atPos;
  std::string name = "", host = "";
  if (!(op.getParameters().size() > 0 &&
	(atPos = op.getParameters()[0].find('@')) > 0)) {
    // input callsign and host interactively
    std::cout << "No callsign@host specified.  Please input them" << std::endl;
    std::cout << "Callsign: ";
    std::cin >> name;
    if (name.size() <= 1) {
      std::cerr << "You must specify a callsign.  Exiting." << std::endl;
      return 1;
    }
    std::cout << "Server to connect to: ";
    std::cin >> host;
    if (host.size() <= 1) {
      std::cerr << "You must specify a host name to connect to.  Exiting." << std::endl;
      return 1;
    }
  } else { // callsign/host on command line
    name = op.getParameters()[0].substr(0, atPos);
    host = op.getParameters()[0].substr(atPos + 1);
  }

  int port = ServerPort;
  int cPos = host.find(':');
  if (cPos != -1) {
    port = atoi(host.substr(cPos + 1).c_str());
    host = host.substr(0, cPos);
  }

  // check that the ui is valid
  uiIter = UIMap::instance().find(uiName);
  if (uiIter == UIMap::instance().end()) {
    std::cerr<<"There is no interface called \""<<uiName<<"\"."<<std::endl;
    return 1;
  }

  // try to connect
  BZAdminClient client(name, host, port);
  if (!client.isValid())
    return 1;
  unsigned int i;
  for (i = 0; i < visibleMsgs.size(); ++i)
    client.showMessageType(visibleMsgs[i]);
  for (i = 0; i < invisibleMsgs.size(); ++i)
    client.ignoreMessageType(invisibleMsgs[i]);

  // if we got commands as arguments, send them and exit
  if (op.getParameters().size() > 1) {
    for (unsigned int i = 1; i < op.getParameters().size(); ++i)
      client.sendMessage(op.getParameters()[i], AllPlayers);

    if (earlyQuit) {
      client.waitForServer();
      return 0;
    }
  }

  // Print a friendly warning
  if (earlyQuit)
    std::cout << "WARNING: didn't quit early, no command line commands" << std::endl;

  // create UI and run the main loop
  BZAdminUI*  ui = uiIter->second(client);
  client.setUI(ui);
  client.runLoop();
  delete ui;

  return 0;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

// interface header
#include "RejoinList.h"

// common headers
#include "TimeKeeper.h"
#include "PlayerInfo.h"
#include "StateDatabase.h"  // for StateDatabase::BZDB_REJOINTIME

// bzfs specific headers
#include "CmdLineOptions.h" // for MaxPlayers & ReplayObservers
#include "RecordReplay.h"
#include "GameKeeper.h"

// it's loathsome to expose private structure in a header
typedef struct RejoinNode {
  char callsign[CallSignLen];
  TimeKeeper joinTime;
} RejoinNode;

RejoinList::RejoinList ()
{
  queue.clear(); // call me paranoid
}

RejoinList::~RejoinList ()
{
  std::list<struct RejoinNode*>::iterator it;
  for (it = queue.begin(); it != queue.end(); it++) {
    RejoinNode *rn = *it;
    delete rn;
  }
  queue.clear();
}

bool RejoinList::add (int playerIndex)
{
  GameKeeper::Player *playerData
    = GameKeeper::Player::getPlayerByIndex(playerIndex);
  if (!playerData)
    return true;
  RejoinNode* rn = new RejoinNode;
  strcpy (rn->callsign, playerData->player.getCallSign());
  rn->joinTime = TimeKeeper::getCurrent();
  queue.push_back (rn);
  return true;
}

float RejoinList::waitTime (int playerIndex)
{
  GameKeeper::Player *playerData
    = GameKeeper::Player::getPlayerByIndex(playerIndex);
  if (!playerData)
    return true;

  std::list<struct RejoinNode*>::iterator it;
  TimeKeeper thenTime = TimeKeeper::getCurrent();
  thenTime += -BZDB.eval(StateDatabase::BZDB_REJOINTIME);

  // remove old entries
  it = queue.begin();
  while (it != queue.end()) {
    RejoinNode *rn = *it;
    if (rn->joinTime <= thenTime) {
      delete rn;
      it = queue.erase(it);
      continue;
    }
    it++;
  }

  const char *callsign = playerData->player.getCallSign();
  float value = 0.0f;
  it = queue.begin();
  while (it != queue.end()) {
    RejoinNode *rn = *it;
    if (strcasecmp (rn->callsign, callsign) == 0) {
      value = rn->joinTime - thenTime;
    }
    it++;
  }

  return value;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>float(true) == ?<commit_after>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

// interface header
#include "RejoinList.h"

// common headers
#include "TimeKeeper.h"
#include "PlayerInfo.h"
#include "StateDatabase.h"  // for StateDatabase::BZDB_REJOINTIME

// bzfs specific headers
#include "CmdLineOptions.h" // for MaxPlayers & ReplayObservers
#include "RecordReplay.h"
#include "GameKeeper.h"

// it's loathsome to expose private structure in a header
typedef struct RejoinNode {
  char callsign[CallSignLen];
  TimeKeeper joinTime;
} RejoinNode;

RejoinList::RejoinList ()
{
  queue.clear(); // call me paranoid
}

RejoinList::~RejoinList ()
{
  std::list<struct RejoinNode*>::iterator it;
  for (it = queue.begin(); it != queue.end(); it++) {
    RejoinNode *rn = *it;
    delete rn;
  }
  queue.clear();
}

bool RejoinList::add (int playerIndex)
{
  GameKeeper::Player *playerData
    = GameKeeper::Player::getPlayerByIndex(playerIndex);
  if (playerData == NULL) {
    return false;
  }
  RejoinNode* rn = new RejoinNode;
  strcpy (rn->callsign, playerData->player.getCallSign());
  rn->joinTime = TimeKeeper::getCurrent();
  queue.push_back (rn);
  return true;
}

float RejoinList::waitTime (int playerIndex)
{
  GameKeeper::Player *playerData
    = GameKeeper::Player::getPlayerByIndex(playerIndex);
  if (playerData == NULL) {
    return 0.0f;
  }

  std::list<struct RejoinNode*>::iterator it;
  TimeKeeper thenTime = TimeKeeper::getCurrent();
  thenTime += -BZDB.eval(StateDatabase::BZDB_REJOINTIME);

  // remove old entries
  it = queue.begin();
  while (it != queue.end()) {
    RejoinNode *rn = *it;
    if (rn->joinTime <= thenTime) {
      delete rn;
      it = queue.erase(it);
      continue;
    }
    it++;
  }

  const char *callsign = playerData->player.getCallSign();
  float value = 0.0f;
  it = queue.begin();
  while (it != queue.end()) {
    RejoinNode *rn = *it;
    if (strcasecmp (rn->callsign, callsign) == 0) {
      value = rn->joinTime - thenTime;
    }
    it++;
  }

  return value;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>