Skip to content

Commit 65e37f7

Browse files
authored
Merge pull request #66013 from ahoppen/ahoppen/sourcekitd-barriers
[sourcekitd] Allow client to enable use of dispatch barriers for open/edit/close on the message handling queue
2 parents 208eaac + d4ffe40 commit 65e37f7

File tree

6 files changed

+108
-32
lines changed

6 files changed

+108
-32
lines changed

tools/SourceKit/include/SourceKit/Core/Context.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,6 @@ class RequestTracker {
9090
}
9191

9292
public:
93-
/// Returns \c true if the request with the given \p CancellationToken has
94-
/// already been cancelled.
95-
bool isCancelled(SourceKitCancellationToken CancellationToken) {
96-
if (!CancellationToken) {
97-
return false;
98-
}
99-
llvm::sys::ScopedLock L(RequestsMtx);
100-
return isCancelledImpl(CancellationToken);
101-
}
102-
10393
/// Adds a \p CancellationHandler that will be called when the request
10494
/// associated with the \p CancellationToken is cancelled.
10595
/// If that request has already been cancelled when this method is called,

tools/SourceKit/tools/sourcekitd/bin/InProc/sourcekitdInProc.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@
3434

3535
using namespace SourceKit;
3636

37+
/// The queue on which the all incoming requests will be handled. If barriers
38+
/// are enabled, open/edit/close requests will be dispatched as barriers on this
39+
/// queue.
40+
WorkQueue *msgHandlingQueue = nullptr;
41+
42+
/// Whether request barriers have been enabled, i.e. whether open/edit/close
43+
/// requests should be dispatched as barriers.
44+
static bool RequestBarriersEnabled = false;
45+
3746
static void postNotification(sourcekitd_response_t Notification);
3847

3948
static void getToolchainPrefixPath(llvm::SmallVectorImpl<char> &Path) {
@@ -96,6 +105,9 @@ static std::string getDiagnosticDocumentationPath() {
96105
}
97106

98107
void sourcekitd_initialize(void) {
108+
assert(msgHandlingQueue == nullptr && "Cannot initialize service twice");
109+
msgHandlingQueue = new WorkQueue(WorkQueue::Dequeuing::Concurrent,
110+
"sourcekitdInProc.msgHandlingQueue");
99111
if (sourcekitd::initializeClient()) {
100112
LOG_INFO_FUNC(High, "initializing");
101113
sourcekitd::initializeService(getSwiftExecutablePath(), getRuntimeLibPath(),
@@ -154,7 +166,7 @@ void sourcekitd_send_request(sourcekitd_object_t req,
154166

155167
sourcekitd_request_retain(req);
156168
receiver = Block_copy(receiver);
157-
WorkQueue::dispatchConcurrent([=] {
169+
auto handler = [=] {
158170
sourcekitd::handleRequest(req, /*CancellationToken=*/request_handle,
159171
[=](sourcekitd_response_t resp) {
160172
// The receiver accepts ownership of the
@@ -163,7 +175,20 @@ void sourcekitd_send_request(sourcekitd_object_t req,
163175
Block_release(receiver);
164176
});
165177
sourcekitd_request_release(req);
166-
});
178+
};
179+
180+
if (sourcekitd::requestIsEnableBarriers(req)) {
181+
RequestBarriersEnabled = true;
182+
sourcekitd::sendBarriersEnabledResponse([=](sourcekitd_response_t resp) {
183+
// The receiver accepts ownership of the response.
184+
receiver(resp);
185+
Block_release(receiver);
186+
});
187+
} else if (RequestBarriersEnabled && sourcekitd::requestIsBarrier(req)) {
188+
msgHandlingQueue->dispatchBarrier(handler);
189+
} else {
190+
msgHandlingQueue->dispatchConcurrent(handler);
191+
}
167192
}
168193

169194
void sourcekitd_cancel_request(sourcekitd_request_handle_t handle) {

tools/SourceKit/tools/sourcekitd/bin/XPC/Service/XPCService.cpp

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ using namespace SourceKit;
3232
using namespace sourcekitd;
3333

3434
static xpc_connection_t MainConnection = nullptr;
35+
static bool RequestBarriersEnabled = false;
3536

3637
static void postNotification(sourcekitd_response_t Notification) {
3738
xpc_connection_t peer = MainConnection;
@@ -255,43 +256,66 @@ static void sourcekitdServer_peer_event_handler(xpc_connection_t peer,
255256
assert(type == XPC_TYPE_DICTIONARY);
256257
// Handle the message
257258
xpc_retain(event);
258-
dispatch_async(msgHandlingQueue, ^{
259-
if (xpc_object_t contents =
260-
xpc_dictionary_get_value(event, xpc::KeyMsg)) {
259+
if (xpc_object_t contents = xpc_dictionary_get_value(event, xpc::KeyMsg)) {
260+
assert(xpc_get_type(contents) == XPC_TYPE_ARRAY);
261+
sourcekitd_object_t req = xpc_array_get_value(contents, 0);
262+
263+
void (^handler)(void) = ^{
261264
SourceKitCancellationToken cancelToken =
262265
reinterpret_cast<SourceKitCancellationToken>(
263266
xpc_dictionary_get_uint64(event, xpc::KeyCancelToken));
264267
auto Responder = std::make_shared<XPCResponder>(event, peer);
265268
xpc_release(event);
266269

267-
assert(xpc_get_type(contents) == XPC_TYPE_ARRAY);
268-
sourcekitd_object_t req = xpc_array_get_value(contents, 0);
269270
sourcekitd::handleRequest(req, /*CancellationToken=*/cancelToken,
270271
[Responder](sourcekitd_response_t response) {
271272
Responder->sendReply(response);
272273
});
273-
} else if (xpc_object_t contents =
274-
xpc_dictionary_get_value(event, "ping")) {
274+
};
275+
276+
if (sourcekitd::requestIsEnableBarriers(req)) {
277+
dispatch_barrier_async(msgHandlingQueue, ^{
278+
auto Responder = std::make_shared<XPCResponder>(event, peer);
279+
xpc_release(event);
280+
RequestBarriersEnabled = true;
281+
sourcekitd::sendBarriersEnabledResponse([Responder](sourcekitd_response_t response) {
282+
Responder->sendReply(response);
283+
});
284+
});
285+
} else if (RequestBarriersEnabled && sourcekitd::requestIsBarrier(req)) {
286+
dispatch_barrier_async(msgHandlingQueue, handler);
287+
} else {
288+
dispatch_async(msgHandlingQueue, handler);
289+
}
290+
} else if (xpc_object_t contents =
291+
xpc_dictionary_get_value(event, "ping")) {
292+
dispatch_async(msgHandlingQueue, ^{
275293
// Ping back.
276294
xpc_object_t reply = xpc_dictionary_create_reply(event);
277295
xpc_release(event);
278296
assert(reply);
279297
xpc_connection_send_message(peer, reply);
280298
xpc_release(reply);
281-
} else if (SourceKitCancellationToken cancelToken =
282-
reinterpret_cast<SourceKitCancellationToken>(
283-
xpc_dictionary_get_uint64(event,
284-
xpc::KeyCancelRequest))) {
299+
});
300+
} else if (SourceKitCancellationToken cancelToken =
301+
reinterpret_cast<SourceKitCancellationToken>(
302+
xpc_dictionary_get_uint64(event,
303+
xpc::KeyCancelRequest))) {
304+
// Execute cancellation on a queue other than `msgHandling` so that we
305+
// don’t block the cancellation of a request with a barrier
306+
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
285307
sourcekitd::cancelRequest(/*CancellationToken=*/cancelToken);
286-
} else if (SourceKitCancellationToken cancelToken =
287-
reinterpret_cast<SourceKitCancellationToken>(
288-
xpc_dictionary_get_uint64(
289-
event, xpc::KeyDisposeRequestHandle))) {
308+
});
309+
} else if (SourceKitCancellationToken cancelToken =
310+
reinterpret_cast<SourceKitCancellationToken>(
311+
xpc_dictionary_get_uint64(
312+
event, xpc::KeyDisposeRequestHandle))) {
313+
dispatch_async(msgHandlingQueue, ^{
290314
sourcekitd::disposeCancellationToken(/*CancellationToken=*/cancelToken);
291-
} else {
292-
assert(false && "unexpected message");
293-
}
294-
});
315+
});
316+
} else {
317+
assert(false && "unexpected message");
318+
}
295319
}
296320
}
297321

tools/SourceKit/tools/sourcekitd/include/sourcekitd/Service.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,21 @@ void cancelRequest(SourceKitCancellationToken CancellationToken);
4545

4646
void disposeCancellationToken(SourceKitCancellationToken CancellationToken);
4747

48+
/// Returns \c true if \p Request is of a request kind that should be issued as
49+
/// a dispatch barrier of the message handling queue. In practice, this returns
50+
/// \c true for open, edit and close requets.
51+
///
52+
/// This does not check if dispatch barriers have been enabled by the sourckitd
53+
/// client.
54+
bool requestIsBarrier(sourcekitd_object_t Request);
55+
56+
/// Returns \c true if this is a request to enable dispatch barriers in
57+
/// sourcekitd.
58+
bool requestIsEnableBarriers(sourcekitd_object_t Request);
59+
60+
/// Send the response that request barriers have been enabled to \p Receiver.
61+
void sendBarriersEnabledResponse(ResponseReceiver Receiver);
62+
4863
} // namespace sourcekitd
4964

5065
#endif // LLVM_SOURCEKITD_SERVICE_H

tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,26 @@ void sourcekitd::disposeCancellationToken(
405405
getGlobalContext().getRequestTracker()->stopTracking(CancellationToken);
406406
}
407407
408+
bool sourcekitd::requestIsBarrier(sourcekitd_object_t ReqObj) {
409+
RequestDict Req(ReqObj);
410+
sourcekitd_uid_t ReqUID = Req.getUID(KeyRequest);
411+
return ReqUID == RequestEditorOpen || ReqUID == RequestEditorReplaceText ||
412+
ReqUID == RequestEditorClose;
413+
}
414+
415+
bool sourcekitd::requestIsEnableBarriers(sourcekitd_object_t ReqObj) {
416+
RequestDict Req(ReqObj);
417+
sourcekitd_uid_t ReqUID = Req.getUID(KeyRequest);
418+
return ReqUID == RequestEnableRequestBarriers;
419+
}
420+
421+
void sourcekitd::sendBarriersEnabledResponse(ResponseReceiver Receiver) {
422+
ResponseBuilder RespBuilder;
423+
auto Elem = RespBuilder.getDictionary();
424+
Elem.setBool(KeyBarriersEnabled, true);
425+
Receiver(RespBuilder.createResponse());
426+
}
427+
408428
static std::unique_ptr<llvm::MemoryBuffer> getInputBufForRequest(
409429
Optional<StringRef> SourceFile, Optional<StringRef> SourceText,
410430
const Optional<VFSOptions> &vfsOptions, llvm::SmallString<64> &ErrBuf) {

utils/gyb_sourcekit_support/UIDs.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,8 @@ def __init__(self, internal_name, external_name):
207207
# in this time. For cancellation testing purposes.
208208
KEY('SimulateLongRequest', 'key.simulate_long_request'),
209209
KEY('IsSynthesized', 'key.is_synthesized'),
210-
KEY('BufferName', 'key.buffer_name')
210+
KEY('BufferName', 'key.buffer_name'),
211+
KEY('BarriersEnabled', 'key.barriers_enabled'),
211212
]
212213

213214

@@ -272,6 +273,7 @@ def __init__(self, internal_name, external_name):
272273
REQUEST('Diagnostics', 'source.request.diagnostics'),
273274
REQUEST('Compile', 'source.request.compile'),
274275
REQUEST('CompileClose', 'source.request.compile.close'),
276+
REQUEST('EnableRequestBarriers', 'source.request.enable_request_barriers'),
275277
]
276278

277279

0 commit comments

Comments
 (0)