michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // Original author: ekr@rtfm.com michael@0: michael@0: #ifndef runnable_utils_h__ michael@0: #define runnable_utils_h__ michael@0: michael@0: #include "nsThreadUtils.h" michael@0: #include "mozilla/RefPtr.h" michael@0: michael@0: // Abstract base class for all of our templates michael@0: namespace mozilla { michael@0: michael@0: class runnable_args_base : public nsRunnable { michael@0: public: michael@0: NS_IMETHOD Run() = 0; michael@0: virtual bool returns_value() const { return false; } michael@0: }; michael@0: michael@0: // The generated file contains four major function templates michael@0: // (in variants for arbitrary numbers of arguments up to 10, michael@0: // which is why it is machine generated). The four templates michael@0: // are: michael@0: // michael@0: // WrapRunnable(o, m, ...) -- wraps a member function m of an object ptr o michael@0: // WrapRunnableRet(o, m, ..., r) -- wraps a member function m of an object ptr o michael@0: // the function returns something that can michael@0: // be assigned to *r michael@0: // WrapRunnableNM(f, ...) -- wraps a function f michael@0: // WrapRunnableNMRet(f, ..., r) -- wraps a function f that returns something michael@0: // that can be assigned to *r michael@0: // michael@0: // All of these template functions return a Runnable* which can be passed michael@0: // to Dispatch(). michael@0: #include "runnable_utils_generated.h" michael@0: michael@0: // Temporary hack. Really we want to have a template which will do this michael@0: static inline nsresult RUN_ON_THREAD(nsIEventTarget *thread, nsIRunnable *runnable, uint32_t flags) { michael@0: RefPtr runnable_ref(runnable); michael@0: if (thread) { michael@0: bool on; michael@0: nsresult rv; michael@0: rv = thread->IsOnCurrentThread(&on); michael@0: michael@0: // If the target thread has already shut down, we don't want to assert. michael@0: if (rv != NS_ERROR_NOT_INITIALIZED) { michael@0: MOZ_ASSERT(NS_SUCCEEDED(rv)); michael@0: } michael@0: michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: if(!on) { michael@0: return thread->Dispatch(runnable_ref, flags); michael@0: } michael@0: } michael@0: return runnable_ref->Run(); michael@0: } michael@0: michael@0: static inline nsresult RUN_ON_THREAD(nsIEventTarget *thread, runnable_args_base *runnable, uint32_t flags) { michael@0: // Detect attempts to return a value when in async mode, since this michael@0: // most likely means someone is trying to assign to a heap variable michael@0: // which is now out of scope. michael@0: MOZ_ASSERT((!(runnable->returns_value()) || (flags != NS_DISPATCH_NORMAL))); michael@0: michael@0: return RUN_ON_THREAD(thread, static_cast(runnable), flags); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: #define ASSERT_ON_THREAD(t) do { \ michael@0: if (t) { \ michael@0: bool on; \ michael@0: nsresult rv; \ michael@0: rv = t->IsOnCurrentThread(&on); \ michael@0: MOZ_ASSERT(NS_SUCCEEDED(rv)); \ michael@0: MOZ_ASSERT(on); \ michael@0: } \ michael@0: } while(0) michael@0: #else michael@0: #define ASSERT_ON_THREAD(t) michael@0: #endif michael@0: michael@0: } /* namespace mozilla */ michael@0: michael@0: #endif