f14bc45d3614c7c6635eb17ab0e272816a1373dd
[WebKit-https.git] / Source / WTF / wtf / ThreadMessage.cpp
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "ThreadMessage.h"
28
29 #if USE(PTHREADS)
30
31 #include <fcntl.h>
32 #include <unistd.h>
33
34 #include <wtf/DataLog.h>
35 #include <wtf/Lock.h>
36 #include <wtf/Locker.h>
37 #include <wtf/threads/Signals.h>
38
39
40 namespace WTF {
41
42 using Node = LocklessBag<ThreadMessageData*>::Node;
43
44 class ThreadMessageData {
45     WTF_MAKE_FAST_ALLOCATED;
46 public:
47     ThreadMessageData(const ThreadMessage& m)
48         : ran(nullptr)
49         , message(m)
50     {
51     }
52
53     Atomic<Node*> ran;
54     const ThreadMessage& message;
55 };
56
57 enum FileDescriptor {
58     Read,
59     Write,
60     NumberOfFileDescriptors,
61 };
62
63 static int fileDescriptors[NumberOfFileDescriptors];
64 static const char* const magicByte = "d";
65
66
67 void initializeThreadMessages()
68 {
69     int result = pipe(fileDescriptors);
70     RELEASE_ASSERT(!result);
71
72     int flags = fcntl(fileDescriptors[Write], F_GETFL);
73     result = fcntl(fileDescriptors[Write], F_SETFL, flags | O_NONBLOCK | O_APPEND);
74     flags = fcntl(fileDescriptors[Write], F_GETFL);
75     RELEASE_ASSERT(result != -1);
76     RELEASE_ASSERT((flags & O_NONBLOCK) && (flags & O_APPEND));
77
78     flags = fcntl(fileDescriptors[Read], F_GETFL);
79     result = fcntl(fileDescriptors[Read], F_SETFL, flags & ~O_NONBLOCK);
80     flags = fcntl(fileDescriptors[Read], F_GETFL);
81     RELEASE_ASSERT(result != -1);
82     RELEASE_ASSERT(!(flags & O_NONBLOCK));
83 }
84
85 SUPPRESS_ASAN
86 MessageStatus sendMessageScoped(Thread& thread, const ThreadMessage& message)
87 {
88     constexpr Signal signal = Signal::Usr;
89     static std::once_flag once;
90     std::call_once(once, [] {
91         installSignalHandler(signal, [] (int, siginfo_t* info, void* uap) {
92             Thread* thread = Thread::currentMayBeNull();
93
94             if (!thread) {
95                 dataLogLn("We somehow got a message on a thread that didn't have a WTF::Thread initialized, we probably deadlocked, halp.");
96                 return SignalAction::NotHandled;
97             }
98
99             // Node should be deleted in the sender thread. Deleting Nodes in signal handler causes dead lock.
100             thread->threadMessages().consumeAllWithNode([&] (ThreadMessageData* data, Node* node) {
101                 data->message(info, static_cast<ucontext_t*>(uap));
102                 // By setting ran variable, (1) the sender acknowledges the completion and
103                 // (2) gets the Node to be deleted.
104                 data->ran.store(node);
105             });
106
107             while (write(fileDescriptors[Write], magicByte, 1) == -1)
108                 ASSERT(errno == EAGAIN);
109
110             return SignalAction::Handled;
111         });
112     });
113
114
115     // Since we are guarenteed not to return until we get a response from the other thread this is ok.
116     ThreadMessageData data(message);
117
118     thread.threadMessages().add(&data);
119     bool result = thread.signal(toSystemSignal(signal));
120     if (!result)
121         return MessageStatus::ThreadExited;
122     RELEASE_ASSERT(result);
123
124     static StaticLock readLock;
125     while (true) {
126         LockHolder locker(readLock);
127         constexpr size_t bufferSize = 16;
128         char buffer[bufferSize];
129
130         // It's always safe to clear the pipe because only one thread can ever block trying to read
131         // from the pipe. Thus, each byte we clear from the pipe actually just corresponds to some task
132         // that has already finished. We actively want to ensure that the pipe does not overfill because
133         // otherwise our writers might spin trying to write.
134         auto clearPipe = [&] {
135             int flags = fcntl(fileDescriptors[Read], F_GETFL);
136             ASSERT(!(flags & O_NONBLOCK));
137             fcntl(fileDescriptors[Read], F_SETFL, flags | O_NONBLOCK);
138
139             while (read(fileDescriptors[Read], buffer, bufferSize) != -1) { }
140             ASSERT(errno == EAGAIN);
141
142             fcntl(fileDescriptors[Read], F_SETFL, flags);
143         };
144
145         if (Node* node = data.ran.load()) {
146             clearPipe();
147             delete node;
148             return MessageStatus::MessageRan;
149         }
150
151         int ret = read(fileDescriptors[Read], buffer, 1);
152         UNUSED_PARAM(ret);
153         ASSERT(buffer[0] == magicByte[0]);
154         clearPipe();
155     }
156     RELEASE_ASSERT_NOT_REACHED();
157 }
158
159 } // namespace WTF
160
161 #endif // USE(PTHREADS)