Changeset 218080 in webkit


Ignore:
Timestamp:
Jun 11, 2017, 5:47:18 PM (8 years ago)
Author:
Yusuke Suzuki
Message:

[WTF] Make ThreadMessage portable
https://bugs.webkit.org/show_bug.cgi?id=172073

Reviewed by Keith Miller.

Source/JavaScriptCore:

  • runtime/MachineContext.h:

(JSC::MachineContext::stackPointer):

  • tools/CodeProfiling.cpp:

(JSC::profilingTimer):

Source/WTF:

Recently, we change ThreadMessage semantics: message handler
can be executed in the sender thread.
This allows ThreadMessage to be implemented in a portable way.

This patch implements ThreadMessage for all the platforms.
We use platform-independent Thread APIs, suspend(), resume(),
and getRegisters().

  • wtf/PlatformRegisters.h:

(WTF::registersFromUContext):

  • wtf/ThreadMessage.cpp:

(WTF::sendMessageScoped):
(WTF::ThreadMessageData::ThreadMessageData): Deleted.
(): Deleted.
(WTF::initializeThreadMessages): Deleted.
(WTF::sendMessageUsingSignal): Deleted.
(WTF::sendMessageUsingMach): Deleted.
(WTF::deliverMessagesUsingMach): Deleted.

  • wtf/ThreadMessage.h:
  • wtf/Threading.cpp:

(WTF::initializeThreading):

  • wtf/Threading.h:

(WTF::Thread::threadMessages): Deleted.

  • wtf/ThreadingPthreads.cpp:

(WTF::Thread::signalHandlerSuspendResume):
(WTF::threadStateMetadata):
(WTF::Thread::getRegisters):

  • wtf/threads/Signals.cpp:

(WTF::handleSignalsWithMach):

Location:
trunk/Source
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r218070 r218080  
     12017-06-11  Yusuke Suzuki  <[email protected]>
     2
     3        [WTF] Make ThreadMessage portable
     4        https://bugs.webkit.org/show_bug.cgi?id=172073
     5
     6        Reviewed by Keith Miller.
     7
     8        * runtime/MachineContext.h:
     9        (JSC::MachineContext::stackPointer):
     10        * tools/CodeProfiling.cpp:
     11        (JSC::profilingTimer):
     12
    1132017-06-11  Yusuke Suzuki  <[email protected]>
    214
  • trunk/Source/JavaScriptCore/runtime/MachineContext.h

    r215270 r218080  
    3434namespace MachineContext {
    3535
    36 
     36void* stackPointer(const PlatformRegisters&);
     37
     38#if OS(WINDOWS) || HAVE(MACHINE_CONTEXT)
    3739void*& stackPointer(PlatformRegisters&);
    38 void* stackPointer(const PlatformRegisters&);
    39 
    40 #if OS(WINDOWS) || HAVE(MACHINE_CONTEXT)
    4140void*& framePointer(PlatformRegisters&);
    4241void* framePointer(const PlatformRegisters&);
     
    6564#endif // OS(WINDOWS) || HAVE(MACHINE_CONTEXT)
    6665
     66#if OS(WINDOWS) || HAVE(MACHINE_CONTEXT)
    6767inline void*& stackPointer(PlatformRegisters& regs)
    6868{
     
    112112#elif HAVE(MACHINE_CONTEXT)
    113113    return stackPointer(regs.machineContext);
    114 #else
     114#endif
     115}
     116
     117inline void* stackPointer(const PlatformRegisters& regs)
     118{
     119    return stackPointer(const_cast<PlatformRegisters&>(regs));
     120}
     121#else // not OS(WINDOWS) || HAVE(MACHINE_CONTEXT)
     122inline void* stackPointer(const PlatformRegisters& regs)
     123{
    115124    return regs.stackPointer;
    116 #endif
    117 }
    118 
    119 inline void* stackPointer(const PlatformRegisters& regs)
    120 {
    121     return stackPointer(const_cast<PlatformRegisters&>(regs));
    122 }
    123 
     125}
     126#endif // OS(WINDOWS) || HAVE(MACHINE_CONTEXT)
    124127
    125128#if HAVE(MACHINE_CONTEXT)
  • trunk/Source/JavaScriptCore/tools/CodeProfiling.cpp

    r215318 r218080  
    7171static void profilingTimer(int, siginfo_t*, void* uap)
    7272{
    73     mcontext_t context = static_cast<ucontext_t*>(uap)->uc_mcontext;
     73    PlatformRegisters& platformRegisters = WTF::registersFromUContext(static_cast<ucontext_t*>(uap));
    7474    CodeProfiling::sample(
    75         MachineContext::instructionPointer(context),
    76         reinterpret_cast<void**>(MachineContext::framePointer(context)));
     75        MachineContext::instructionPointer(platformRegisters),
     76        reinterpret_cast<void**>(MachineContext::framePointer(platformRegisters)));
    7777}
    7878#endif
  • trunk/Source/WTF/ChangeLog

    r218069 r218080  
     12017-06-11  Yusuke Suzuki  <[email protected]>
     2
     3        [WTF] Make ThreadMessage portable
     4        https://bugs.webkit.org/show_bug.cgi?id=172073
     5
     6        Reviewed by Keith Miller.
     7
     8        Recently, we change ThreadMessage semantics: message handler
     9        can be executed in the sender thread.
     10        This allows ThreadMessage to be implemented in a portable way.
     11
     12        This patch implements ThreadMessage for all the platforms.
     13        We use platform-independent Thread APIs, suspend(), resume(),
     14        and getRegisters().
     15
     16        * wtf/PlatformRegisters.h:
     17        (WTF::registersFromUContext):
     18        * wtf/ThreadMessage.cpp:
     19        (WTF::sendMessageScoped):
     20        (WTF::ThreadMessageData::ThreadMessageData): Deleted.
     21        (): Deleted.
     22        (WTF::initializeThreadMessages): Deleted.
     23        (WTF::sendMessageUsingSignal): Deleted.
     24        (WTF::sendMessageUsingMach): Deleted.
     25        (WTF::deliverMessagesUsingMach): Deleted.
     26        * wtf/ThreadMessage.h:
     27        * wtf/Threading.cpp:
     28        (WTF::initializeThreading):
     29        * wtf/Threading.h:
     30        (WTF::Thread::threadMessages): Deleted.
     31        * wtf/ThreadingPthreads.cpp:
     32        (WTF::Thread::signalHandlerSuspendResume):
     33        (WTF::threadStateMetadata):
     34        (WTF::Thread::getRegisters):
     35        * wtf/threads/Signals.cpp:
     36        (WTF::handleSignalsWithMach):
     37
    1382017-06-11  Yusuke Suzuki  <[email protected]>
    239
  • trunk/Source/WTF/wtf/PlatformRegisters.h

    r217669 r218080  
    7575inline PlatformRegisters& registersFromUContext(ucontext_t* ucontext)
    7676{
     77#if CPU(PPC)
     78    return *bitwise_cast<PlatformRegisters*>(ucontext->uc_mcontext.uc_regs);
     79#else
    7780    return *bitwise_cast<PlatformRegisters*>(&ucontext->uc_mcontext);
     81#endif
    7882}
    7983
  • trunk/Source/WTF/wtf/ThreadMessage.cpp

    r217669 r218080  
    2727#include "ThreadMessage.h"
    2828
    29 #if USE(PTHREADS)
    30 
    31 #include <fcntl.h>
    32 #include <unistd.h>
    33 
    34 #include <wtf/DataLog.h>
    3529#include <wtf/Lock.h>
    3630#include <wtf/Locker.h>
    37 #include <wtf/threads/Signals.h>
    38 
    39 #if HAVE(MACH_EXCEPTIONS)
    40 #include <mach/thread_act.h>
    41 #endif
    4231
    4332namespace WTF {
    4433
    45 using Node = LocklessBag<ThreadMessageData*>::Node;
    46 
    47 class ThreadMessageData {
    48     WTF_MAKE_FAST_ALLOCATED;
    49 public:
    50     ThreadMessageData(const ThreadMessage& m)
    51         : ran(nullptr)
    52         , message(m)
    53     {
    54     }
    55 
    56     Atomic<Node*> ran;
    57     const ThreadMessage& message;
    58 };
    59 
    60 enum FileDescriptor {
    61     Read,
    62     Write,
    63     NumberOfFileDescriptors,
    64 };
    65 
    66 static int fileDescriptors[NumberOfFileDescriptors];
    67 static const char* const magicByte = "d";
    68 
    69 
    70 void initializeThreadMessages()
    71 {
    72     int result = pipe(fileDescriptors);
    73     RELEASE_ASSERT(!result);
    74 
    75     int flags = fcntl(fileDescriptors[Write], F_GETFL);
    76     result = fcntl(fileDescriptors[Write], F_SETFL, flags | O_NONBLOCK | O_APPEND);
    77     flags = fcntl(fileDescriptors[Write], F_GETFL);
    78     RELEASE_ASSERT(result != -1);
    79     RELEASE_ASSERT((flags & O_NONBLOCK) && (flags & O_APPEND));
    80 
    81     flags = fcntl(fileDescriptors[Read], F_GETFL);
    82     result = fcntl(fileDescriptors[Read], F_SETFL, flags & ~O_NONBLOCK);
    83     flags = fcntl(fileDescriptors[Read], F_GETFL);
    84     RELEASE_ASSERT(result != -1);
    85     RELEASE_ASSERT(!(flags & O_NONBLOCK));
    86 }
    87 
    88 SUPPRESS_ASAN
    89 static MessageStatus sendMessageUsingSignal(Thread& thread, const ThreadMessage& message)
    90 {
    91     constexpr Signal signal = Signal::Usr;
    92     static std::once_flag once;
    93     std::call_once(once, [] {
    94         installSignalHandler(signal, [] (Signal, SigInfo&, PlatformRegisters& registers) {
    95             Thread* thread = Thread::currentMayBeNull();
    96 
    97             if (!thread) {
    98                 dataLogLn("We somehow got a message on a thread that didn't have a WTF::Thread initialized, we probably deadlocked, halp.");
    99                 return SignalAction::NotHandled;
    100             }
    101 
    102             // Node should be deleted in the sender thread. Deleting Nodes in signal handler causes dead lock.
    103             thread->threadMessages().consumeAllWithNode([&] (ThreadMessageData* data, Node* node) {
    104                 data->message(registers);
    105                 // By setting ran variable, (1) the sender acknowledges the completion and
    106                 // (2) gets the Node to be deleted.
    107                 data->ran.store(node);
    108             });
    109 
    110             while (write(fileDescriptors[Write], magicByte, 1) == -1)
    111                 ASSERT(errno == EAGAIN);
    112 
    113             return SignalAction::Handled;
    114         });
    115     });
    116 
    117 
    118     // Since we are guarenteed not to return until we get a response from the other thread this is ok.
    119     ThreadMessageData data(message);
    120 
    121     thread.threadMessages().add(&data);
    122     bool result = thread.signal(toSystemSignal(signal));
    123     if (!result)
    124         return MessageStatus::ThreadExited;
    125     RELEASE_ASSERT(result);
    126 
    127     static StaticLock readLock;
    128     while (true) {
    129         LockHolder locker(readLock);
    130         constexpr size_t bufferSize = 16;
    131         char buffer[bufferSize];
    132 
    133         // It's always safe to clear the pipe because only one thread can ever block trying to read
    134         // from the pipe. Thus, each byte we clear from the pipe actually just corresponds to some task
    135         // that has already finished. We actively want to ensure that the pipe does not overfill because
    136         // otherwise our writers might spin trying to write.
    137         auto clearPipe = [&] {
    138             int flags = fcntl(fileDescriptors[Read], F_GETFL);
    139             ASSERT(!(flags & O_NONBLOCK));
    140             fcntl(fileDescriptors[Read], F_SETFL, flags | O_NONBLOCK);
    141 
    142             while (read(fileDescriptors[Read], buffer, bufferSize) != -1) { }
    143             ASSERT(errno == EAGAIN);
    144 
    145             fcntl(fileDescriptors[Read], F_SETFL, flags);
    146         };
    147 
    148         if (Node* node = data.ran.load()) {
    149             clearPipe();
    150             delete node;
    151             return MessageStatus::MessageRan;
    152         }
    153 
    154         int ret = read(fileDescriptors[Read], buffer, 1);
    155         UNUSED_PARAM(ret);
    156         ASSERT(buffer[0] == magicByte[0]);
    157         clearPipe();
    158     }
    159     RELEASE_ASSERT_NOT_REACHED();
    160 }
    161 
    162 #if HAVE(MACH_EXCEPTIONS)
    163 static MessageStatus sendMessageUsingMach(Thread& thread, const ThreadMessage& message)
     34MessageStatus sendMessageScoped(Thread& thread, const ThreadMessage& message)
    16435{
    16536    static StaticLock messageLock;
     
    17950}
    18051
    181 static bool useMach = false;
    182 void deliverMessagesUsingMach()
    183 {
    184     useMach = true;
    185 }
    186 
    187 #endif // HAVE(MACH_EXCEPTIONS)
    188 
    189 MessageStatus sendMessageScoped(Thread& thread, const ThreadMessage& message)
    190 {
    191 #if HAVE(MACH_EXCEPTIONS)
    192     if (useMach)
    193         return sendMessageUsingMach(thread, message);
    194 #endif
    195     return sendMessageUsingSignal(thread, message);
    196 }
    197 
    198 
    19952} // namespace WTF
    200 
    201 #endif // USE(PTHREADS)
  • trunk/Source/WTF/wtf/ThreadMessage.h

    r217669 r218080  
    3030#include <wtf/Threading.h>
    3131
    32 #if USE(PTHREADS)
    33 
    3432namespace WTF {
    3533
    36 void initializeThreadMessages();
    37 
    38 class ThreadMessageData;
    3934using ThreadMessage = ScopedLambda<void(PlatformRegisters&)>;
    4035
     
    5651}
    5752
    58 #if HAVE(MACH_EXCEPTIONS)
    59 void deliverMessagesUsingMach();
    60 #endif
    61 
    6253} // namespace WTF
    6354
    6455using WTF::sendMessage;
    65 
    66 #endif // USE(PTHREADS)
  • trunk/Source/WTF/wtf/Threading.cpp

    r218012 r218080  
    180180        initializeDates();
    181181        Thread::initializePlatformThreading();
    182 #if USE(PTHREADS)
    183         initializeThreadMessages();
    184 #endif
    185182    });
    186183}
  • trunk/Source/WTF/wtf/Threading.h

    r218069 r218080  
    3737#include <wtf/Expected.h>
    3838#include <wtf/Function.h>
    39 #include <wtf/LocklessBag.h>
    4039#include <wtf/PlatformRegisters.h>
    4140#include <wtf/RefPtr.h>
     
    129128    static void initializePlatformThreading();
    130129
    131 #if USE(PTHREADS)
    132     LocklessBag<ThreadMessageData*>& threadMessages() { return m_threadMessages; }
    133 
    134130#if OS(DARWIN)
    135131    mach_port_t machThread() { return m_platformThread; }
    136 #endif
    137132#endif
    138133
     
    183178    pthread_t m_handle;
    184179
    185     LocklessBag<ThreadMessageData*> m_threadMessages;
    186180#if OS(DARWIN)
    187181    mach_port_t m_platformThread;
  • trunk/Source/WTF/wtf/ThreadingPthreads.cpp

    r217431 r218080  
    146146
    147147#if HAVE(MACHINE_CONTEXT)
    148 #if CPU(PPC)
    149     thread->m_platformRegisters = PlatformRegisters { *userContext->uc_mcontext.uc_regs };
    150 #else
    151     thread->m_platformRegisters = PlatformRegisters { userContext->uc_mcontext };
    152 #endif
     148    thread->m_platformRegisters = registersFromUContext(userContext);
    153149#else
    154150    thread->m_platformRegisters = PlatformRegisters { getApproximateStackPointer() };
     
    403399}
    404400
    405 size_t Thread::getRegisters(PlatformRegisters& registers)
    406 {
    407     std::unique_lock<std::mutex> locker(m_mutex);
    408401#if OS(DARWIN)
     402struct ThreadStateMetadata {
     403    unsigned userCount;
     404    thread_state_flavor_t flavor;
     405};
     406
     407static ThreadStateMetadata threadStateMetadata()
     408{
    409409#if CPU(X86)
    410     unsigned userCount = sizeof(registers) / sizeof(int);
     410    unsigned userCount = sizeof(PlatformRegisters) / sizeof(int);
    411411    thread_state_flavor_t flavor = i386_THREAD_STATE;
    412412#elif CPU(X86_64)
     
    428428#error Unknown Architecture
    429429#endif
    430 
    431     kern_return_t result = thread_get_state(m_platformThread, flavor, (thread_state_t)&registers, &userCount);
     430    return ThreadStateMetadata { userCount, flavor };
     431}
     432#endif // OS(DARWIN)
     433
     434size_t Thread::getRegisters(PlatformRegisters& registers)
     435{
     436    std::unique_lock<std::mutex> locker(m_mutex);
     437#if OS(DARWIN)
     438    auto metadata = threadStateMetadata();
     439    kern_return_t result = thread_get_state(m_platformThread, metadata.flavor, (thread_state_t)&registers, &metadata.userCount);
    432440    if (result != KERN_SUCCESS) {
    433441        WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, "JavaScript garbage collection failed because thread_get_state returned an error (%d). This is probably the result of running inside Rosetta, which is not supported.", result);
    434442        CRASH();
    435443    }
    436     return userCount * sizeof(uintptr_t);
     444    return metadata.userCount * sizeof(uintptr_t);
    437445#else
    438446    ASSERT_WITH_MESSAGE(m_suspendCount, "We can get registers only if the thread is suspended.");
  • trunk/Source/WTF/wtf/threads/Signals.cpp

    r217669 r218080  
    209209void handleSignalsWithMach()
    210210{
    211     deliverMessagesUsingMach();
    212211    useMach = true;
    213212}
Note: See TracChangeset for help on using the changeset viewer.