xpcom/glue/nsThreadUtils.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "nsThreadUtils.h"
     8 #include "mozilla/Attributes.h"
     9 #include "mozilla/Likely.h"
    11 #ifdef MOZILLA_INTERNAL_API
    12 # include "nsThreadManager.h"
    13 #else
    14 # include "nsXPCOMCIDInternal.h"
    15 # include "nsIThreadManager.h"
    16 # include "nsServiceManagerUtils.h"
    17 #endif
    19 #ifdef XP_WIN
    20 #include <windows.h>
    21 #include "mozilla/WindowsVersion.h"
    22 using mozilla::IsVistaOrLater;
    23 #elif defined(XP_MACOSX)
    24 #include <sys/resource.h>
    25 #endif
    27 #include <pratom.h>
    28 #include <prthread.h>
    30 #ifndef XPCOM_GLUE_AVOID_NSPR
    32 NS_IMPL_ISUPPORTS(nsRunnable, nsIRunnable)
    34 NS_IMETHODIMP
    35 nsRunnable::Run()
    36 {
    37   // Do nothing
    38   return NS_OK;
    39 }
    41 NS_IMPL_ISUPPORTS(nsCancelableRunnable, nsICancelableRunnable,
    42                   nsIRunnable)
    44 NS_IMETHODIMP
    45 nsCancelableRunnable::Run()
    46 {
    47   // Do nothing
    48   return NS_OK;
    49 }
    51 NS_IMETHODIMP
    52 nsCancelableRunnable::Cancel()
    53 {
    54   // Do nothing
    55   return NS_OK;
    56 }
    58 #endif  // XPCOM_GLUE_AVOID_NSPR
    60 //-----------------------------------------------------------------------------
    62 NS_METHOD
    63 NS_NewThread(nsIThread **result, nsIRunnable *event, uint32_t stackSize)
    64 {
    65   nsCOMPtr<nsIThread> thread;
    66 #ifdef MOZILLA_INTERNAL_API
    67   nsresult rv = nsThreadManager::get()->
    68       nsThreadManager::NewThread(0, stackSize, getter_AddRefs(thread));
    69 #else
    70   nsresult rv;
    71   nsCOMPtr<nsIThreadManager> mgr =
    72       do_GetService(NS_THREADMANAGER_CONTRACTID, &rv);
    73   if (NS_WARN_IF(NS_FAILED(rv)))
    74     return rv;
    76   rv = mgr->NewThread(0, stackSize, getter_AddRefs(thread));
    77 #endif
    78   if (NS_WARN_IF(NS_FAILED(rv)))
    79     return rv;
    81   if (event) {
    82     rv = thread->Dispatch(event, NS_DISPATCH_NORMAL);
    83     if (NS_WARN_IF(NS_FAILED(rv)))
    84       return rv;
    85   }
    87   *result = nullptr;
    88   thread.swap(*result);
    89   return NS_OK;
    90 }
    92 NS_METHOD
    93 NS_GetCurrentThread(nsIThread **result)
    94 {
    95 #ifdef MOZILLA_INTERNAL_API
    96   return nsThreadManager::get()->nsThreadManager::GetCurrentThread(result);
    97 #else
    98   nsresult rv;
    99   nsCOMPtr<nsIThreadManager> mgr =
   100       do_GetService(NS_THREADMANAGER_CONTRACTID, &rv);
   101   if (NS_WARN_IF(NS_FAILED(rv)))
   102     return rv;
   103   return mgr->GetCurrentThread(result);
   104 #endif
   105 }
   107 NS_METHOD
   108 NS_GetMainThread(nsIThread **result)
   109 {
   110 #ifdef MOZILLA_INTERNAL_API
   111   return nsThreadManager::get()->nsThreadManager::GetMainThread(result);
   112 #else
   113   nsresult rv;
   114   nsCOMPtr<nsIThreadManager> mgr =
   115       do_GetService(NS_THREADMANAGER_CONTRACTID, &rv);
   116   if (NS_WARN_IF(NS_FAILED(rv)))
   117     return rv;
   118   return mgr->GetMainThread(result);
   119 #endif
   120 }
   122 #if defined(MOZILLA_INTERNAL_API) && defined(XP_WIN)
   123 extern DWORD gTLSThreadIDIndex;
   124 bool
   125 NS_IsMainThread()
   126 {
   127   return TlsGetValue(gTLSThreadIDIndex) == (void*) mozilla::threads::Main;
   128 }
   129 #elif defined(MOZILLA_INTERNAL_API) && defined(NS_TLS)
   130 #ifdef MOZ_ASAN
   131 // Temporary workaround, see bug 895845
   132 bool NS_IsMainThread()
   133 {
   134   return gTLSThreadID == mozilla::threads::Main;
   135 }
   136 #else
   137 // NS_IsMainThread() is defined inline in MainThreadUtils.h
   138 #endif
   139 #else
   140 #ifdef MOZILLA_INTERNAL_API
   141 bool NS_IsMainThread()
   142 {
   143   bool result = false;
   144   nsThreadManager::get()->nsThreadManager::GetIsMainThread(&result);
   145   return bool(result);
   146 }
   147 #else
   148 bool NS_IsMainThread()
   149 {
   150   bool result = false;
   151   nsCOMPtr<nsIThreadManager> mgr =
   152     do_GetService(NS_THREADMANAGER_CONTRACTID);
   153   if (mgr)
   154     mgr->GetIsMainThread(&result);
   155   return bool(result);
   156 }
   157 #endif
   158 #endif
   160 NS_METHOD
   161 NS_DispatchToCurrentThread(nsIRunnable *event)
   162 {
   163 #ifdef MOZILLA_INTERNAL_API
   164   nsIThread *thread = NS_GetCurrentThread();
   165   if (!thread) { return NS_ERROR_UNEXPECTED; }
   166 #else
   167   nsCOMPtr<nsIThread> thread;
   168   nsresult rv = NS_GetCurrentThread(getter_AddRefs(thread));
   169   if (NS_WARN_IF(NS_FAILED(rv)))
   170     return rv;
   171 #endif
   172   return thread->Dispatch(event, NS_DISPATCH_NORMAL);
   173 }
   175 NS_METHOD
   176 NS_DispatchToMainThread(nsIRunnable *event, uint32_t dispatchFlags)
   177 {
   178   nsCOMPtr<nsIThread> thread;
   179   nsresult rv = NS_GetMainThread(getter_AddRefs(thread));
   180   if (NS_WARN_IF(NS_FAILED(rv)))
   181     return rv;
   182   return thread->Dispatch(event, dispatchFlags);
   183 }
   185 #ifndef XPCOM_GLUE_AVOID_NSPR
   186 NS_METHOD
   187 NS_ProcessPendingEvents(nsIThread *thread, PRIntervalTime timeout)
   188 {
   189   nsresult rv = NS_OK;
   191 #ifdef MOZILLA_INTERNAL_API
   192   if (!thread) {
   193     thread = NS_GetCurrentThread();
   194     if (NS_WARN_IF(!thread))
   195       return NS_ERROR_UNEXPECTED;
   196   }
   197 #else
   198   nsCOMPtr<nsIThread> current;
   199   if (!thread) {
   200     rv = NS_GetCurrentThread(getter_AddRefs(current));
   201     if (NS_WARN_IF(NS_FAILED(rv)))
   202       return rv;
   203     thread = current.get();
   204   }
   205 #endif
   207   PRIntervalTime start = PR_IntervalNow();
   208   for (;;) {
   209     bool processedEvent;
   210     rv = thread->ProcessNextEvent(false, &processedEvent);
   211     if (NS_FAILED(rv) || !processedEvent)
   212       break;
   213     if (PR_IntervalNow() - start > timeout)
   214       break;
   215   }
   216   return rv;
   217 }
   218 #endif // XPCOM_GLUE_AVOID_NSPR
   220 inline bool
   221 hasPendingEvents(nsIThread *thread)
   222 {
   223   bool val;
   224   return NS_SUCCEEDED(thread->HasPendingEvents(&val)) && val;
   225 }
   227 bool
   228 NS_HasPendingEvents(nsIThread *thread)
   229 {
   230   if (!thread) {
   231 #ifndef MOZILLA_INTERNAL_API
   232     nsCOMPtr<nsIThread> current;
   233     NS_GetCurrentThread(getter_AddRefs(current));
   234     return hasPendingEvents(current);
   235 #else
   236     thread = NS_GetCurrentThread();
   237     if (NS_WARN_IF(!thread))
   238       return false;
   239 #endif
   240   }
   241   return hasPendingEvents(thread);
   242 }
   244 bool
   245 NS_ProcessNextEvent(nsIThread *thread, bool mayWait)
   246 {
   247 #ifdef MOZILLA_INTERNAL_API
   248   if (!thread) {
   249     thread = NS_GetCurrentThread();
   250     if (NS_WARN_IF(!thread))
   251       return false;
   252   }
   253 #else
   254   nsCOMPtr<nsIThread> current;
   255   if (!thread) {
   256     NS_GetCurrentThread(getter_AddRefs(current));
   257     if (NS_WARN_IF(!current))
   258       return false;
   259     thread = current.get();
   260   }
   261 #endif
   262   bool val;
   263   return NS_SUCCEEDED(thread->ProcessNextEvent(mayWait, &val)) && val;
   264 }
   266 #ifndef XPCOM_GLUE_AVOID_NSPR
   268 namespace {
   270 class nsNameThreadRunnable MOZ_FINAL : public nsIRunnable
   271 {
   272 public:
   273   nsNameThreadRunnable(const nsACString &name) : mName(name) { }
   275   NS_DECL_THREADSAFE_ISUPPORTS
   276   NS_DECL_NSIRUNNABLE
   278 protected:
   279   const nsCString mName;
   280 };
   282 NS_IMPL_ISUPPORTS(nsNameThreadRunnable, nsIRunnable)
   284 NS_IMETHODIMP
   285 nsNameThreadRunnable::Run()
   286 {
   287   PR_SetCurrentThreadName(mName.BeginReading());
   288   return NS_OK;
   289 }
   291 } // anonymous namespace
   293 void
   294 NS_SetThreadName(nsIThread *thread, const nsACString &name)
   295 {
   296   if (!thread)
   297     return;
   299   thread->Dispatch(new nsNameThreadRunnable(name),
   300                    nsIEventTarget::DISPATCH_NORMAL);
   301 }
   303 #else // !XPCOM_GLUE_AVOID_NSPR
   305 void
   306 NS_SetThreadName(nsIThread *thread, const nsACString &name)
   307 {
   308   // No NSPR, no love.
   309 }
   311 #endif
   313 #ifdef MOZILLA_INTERNAL_API
   314 nsIThread *
   315 NS_GetCurrentThread() {
   316   return nsThreadManager::get()->GetCurrentThread();
   317 }
   318 #endif
   320 // nsThreadPoolNaming
   321 void
   322 nsThreadPoolNaming::SetThreadPoolName(const nsACString & aPoolName,
   323                                       nsIThread * aThread)
   324 {
   325   nsCString name(aPoolName);
   326   name.Append(NS_LITERAL_CSTRING(" #"));
   327   name.AppendInt(++mCounter, 10); // The counter is declared as volatile
   329   if (aThread) {
   330     // Set on the target thread
   331     NS_SetThreadName(aThread, name);
   332   }
   333   else {
   334     // Set on the current thread
   335     PR_SetCurrentThreadName(name.BeginReading());
   336   }
   337 }
   339 // nsAutoLowPriorityIO
   340 nsAutoLowPriorityIO::nsAutoLowPriorityIO()
   341 {
   342 #if defined(XP_WIN)
   343   lowIOPrioritySet = IsVistaOrLater() &&
   344                      SetThreadPriority(GetCurrentThread(),
   345                                        THREAD_MODE_BACKGROUND_BEGIN);
   346 #elif defined(XP_MACOSX)
   347   oldPriority = getiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD);
   348   lowIOPrioritySet = oldPriority != -1 &&
   349                      setiopolicy_np(IOPOL_TYPE_DISK,
   350                                     IOPOL_SCOPE_THREAD,
   351                                     IOPOL_THROTTLE) != -1;
   352 #else
   353   lowIOPrioritySet = false;
   354 #endif
   355 }
   357 nsAutoLowPriorityIO::~nsAutoLowPriorityIO()
   358 {
   359 #if defined(XP_WIN)
   360   if (MOZ_LIKELY(lowIOPrioritySet)) {
   361     // On Windows the old thread priority is automatically restored
   362     SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END);
   363   }
   364 #elif defined(XP_MACOSX)
   365   if (MOZ_LIKELY(lowIOPrioritySet)) {
   366     setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD, oldPriority);
   367   }
   368 #endif
   369 }

mercurial