PageRenderTime 33ms CodeModel.GetById 24ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/llcoros.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 154 lines | 80 code | 12 blank | 62 comment | 13 complexity | 92708b72549f814f4af1749062bf10cf MD5 | raw file
  1/**
  2 * @file   llcoros.cpp
  3 * @author Nat Goodspeed
  4 * @date   2009-06-03
  5 * @brief  Implementation for llcoros.
  6 * 
  7 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  8 * Second Life Viewer Source Code
  9 * Copyright (C) 2010, Linden Research, Inc.
 10 * 
 11 * This library is free software; you can redistribute it and/or
 12 * modify it under the terms of the GNU Lesser General Public
 13 * License as published by the Free Software Foundation;
 14 * version 2.1 of the License only.
 15 * 
 16 * This library is distributed in the hope that it will be useful,
 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 19 * Lesser General Public License for more details.
 20 * 
 21 * You should have received a copy of the GNU Lesser General Public
 22 * License along with this library; if not, write to the Free Software
 23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 24 * 
 25 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 26 * $/LicenseInfo$
 27 */
 28
 29// Precompiled header
 30#include "linden_common.h"
 31// associated header
 32#include "llcoros.h"
 33// STL headers
 34// std headers
 35// external library headers
 36#include <boost/bind.hpp>
 37// other Linden headers
 38#include "llevents.h"
 39#include "llerror.h"
 40#include "stringize.h"
 41
 42LLCoros::LLCoros()
 43{
 44    // Register our cleanup() method for "mainloop" ticks
 45    LLEventPumps::instance().obtain("mainloop").listen(
 46        "LLCoros", boost::bind(&LLCoros::cleanup, this, _1));
 47}
 48
 49bool LLCoros::cleanup(const LLSD&)
 50{
 51    // Walk the mCoros map, checking and removing completed coroutines.
 52    for (CoroMap::iterator mi(mCoros.begin()), mend(mCoros.end()); mi != mend; )
 53    {
 54        // Has this coroutine exited (normal return, exception, exit() call)
 55        // since last tick?
 56        if (mi->second->exited())
 57        {
 58            LL_INFOS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << LL_ENDL;
 59            // The erase() call will invalidate its passed iterator value --
 60            // so increment mi FIRST -- but pass its original value to
 61            // erase(). This is what postincrement is all about.
 62            mCoros.erase(mi++);
 63        }
 64        else
 65        {
 66            // Still live, just skip this entry as if incrementing at the top
 67            // of the loop as usual.
 68            ++mi;
 69        }
 70    }
 71    return false;
 72}
 73
 74std::string LLCoros::generateDistinctName(const std::string& prefix) const
 75{
 76    // Allowing empty name would make getName()'s not-found return ambiguous.
 77    if (prefix.empty())
 78    {
 79        LL_ERRS("LLCoros") << "LLCoros::launch(): pass non-empty name string" << LL_ENDL;
 80    }
 81
 82    // If the specified name isn't already in the map, just use that.
 83    std::string name(prefix);
 84
 85    // Find the lowest numeric suffix that doesn't collide with an existing
 86    // entry. Start with 2 just to make it more intuitive for any interested
 87    // parties: e.g. "joe", "joe2", "joe3"...
 88    for (int i = 2; ; name = STRINGIZE(prefix << i++))
 89    {
 90        if (mCoros.find(name) == mCoros.end())
 91        {
 92            LL_INFOS("LLCoros") << "LLCoros: launching coroutine " << name << LL_ENDL;
 93            return name;
 94        }
 95    }
 96}
 97
 98bool LLCoros::kill(const std::string& name)
 99{
100    CoroMap::iterator found = mCoros.find(name);
101    if (found == mCoros.end())
102    {
103        return false;
104    }
105    // Because this is a boost::ptr_map, erasing the map entry also destroys
106    // the referenced heap object, in this case the boost::coroutine object,
107    // which will terminate the coroutine.
108    mCoros.erase(found);
109    return true;
110}
111
112std::string LLCoros::getNameByID(const void* self_id) const
113{
114    // Walk the existing coroutines, looking for one from which the 'self_id'
115    // passed to us comes.
116    for (CoroMap::const_iterator mi(mCoros.begin()), mend(mCoros.end()); mi != mend; ++mi)
117    {
118        namespace coro_private = boost::coroutines::detail;
119        if (static_cast<void*>(coro_private::coroutine_accessor::get_impl(const_cast<coro&>(*mi->second)).get())
120            == self_id)
121        {
122            return mi->first;
123        }
124    }
125    return "";
126}
127
128/*****************************************************************************
129*   MUST BE LAST
130*****************************************************************************/
131// Turn off MSVC optimizations for just LLCoros::launchImpl() -- see
132// DEV-32777. But MSVC doesn't support push/pop for optimization flags as it
133// does for warning suppression, and we really don't want to force
134// optimization ON for other code even in Debug or RelWithDebInfo builds.
135
136#if LL_MSVC
137// work around broken optimizations
138#pragma warning(disable: 4748)
139#pragma optimize("", off)
140#endif // LL_MSVC
141
142std::string LLCoros::launchImpl(const std::string& prefix, coro* newCoro)
143{
144    std::string name(generateDistinctName(prefix));
145    mCoros.insert(name, newCoro);
146    /* Run the coroutine until its first wait, then return here */
147    (*newCoro)(std::nothrow);
148    return name;
149}
150
151#if LL_MSVC
152// reenable optimizations
153#pragma optimize("", on)
154#endif // LL_MSVC