Sane C++ Libraries
C++ Platform Abstraction Libraries
Loading...
Searching...
No Matches
Async.h
1// Copyright (c) Stefano Cristiano
2// SPDX-License-Identifier: MIT
3#pragma once
4
5#include "../Common/CompilerMacrosExport.h"
6#ifndef SC_EXPORT_LIBRARY_ASYNC
7#define SC_EXPORT_LIBRARY_ASYNC 0
8#endif
9#define SC_ASYNC_EXPORT SC_COMPILER_LIBRARY_EXPORT(SC_EXPORT_LIBRARY_ASYNC)
10
11#include "../Async/Internal/IntrusiveDoubleLinkedList.h"
12#include "../Common/Assert.h"
13#include "../Common/Function.h"
14#include "../Common/OpaqueObject.h"
15#include "../File/File.h"
16#include "../FileSystem/FileSystem.h"
17#include "../Socket/Socket.h"
18#include "../Threading/Atomic.h"
19#include "../Threading/ThreadPool.h"
20#include "AsyncError.h"
21
22namespace SC
23{
24SC_DECLARE_ASSERT_PROVIDER(AsyncAssert, SC_ASYNC_EXPORT);
25
26#define SC_ASYNC_ASSERT_RELEASE(e) SC_ASSERT_PROVIDER_RELEASE(SC::AsyncAssert, e)
27#define SC_ASYNC_ASSERT_DEBUG(e) SC_ASSERT_PROVIDER_DEBUG(SC::AsyncAssert, e)
28#define SC_ASYNC_TRUST_RESULT(expression) SC_ASYNC_ASSERT_RELEASE(expression)
29
30struct ThreadPool;
31struct ThreadPoolTask;
32struct EventObject;
33} // namespace SC
59
62namespace SC
63{
64struct AsyncEventLoop;
65struct AsyncResult;
66struct AsyncSequence;
67struct AsyncTaskSequence;
68
70enum class AsyncThreadPoolMode : uint8_t
71{
72 NativePreferred,
73 ForceThreadPool,
74};
75
76namespace detail
77{
78struct AsyncWinOverlapped;
79struct AsyncWinOverlappedDefinition
80{
81 static constexpr int Windows = sizeof(void*) * 4 + sizeof(uint64_t);
82 static constexpr size_t Alignment = alignof(void*);
83
84 using Object = AsyncWinOverlapped;
85};
86using WinOverlappedOpaque = OpaqueObject<AsyncWinOverlappedDefinition>;
87
88struct AsyncWinWaitDefinition
89{
90 using Handle = FileDescriptor::Handle; // fd
91 static constexpr Handle Invalid = FileDescriptor::Invalid; // invalid fd
92
93 static Result releaseHandle(Handle& waitHandle);
94};
95struct SC_ASYNC_EXPORT WinWaitHandle : public UniqueHandle<AsyncWinWaitDefinition>
96{
97};
98} // namespace detail
99
138struct SC_ASYNC_EXPORT AsyncRequest
139{
140 AsyncRequest* next = nullptr;
141 AsyncRequest* prev = nullptr;
142
143 void setDebugName(const char* newDebugName);
144
146 void executeOn(AsyncSequence& sequence);
147
152 AsyncThreadPoolMode mode = AsyncThreadPoolMode::NativePreferred);
153
156
158 enum class Type : uint8_t
159 {
160 LoopTimeout,
161 LoopWakeUp,
162 LoopWork,
163 ProcessExit,
164 Signal,
165 SocketAccept,
166 SocketConnect,
167 SocketSend,
168 SocketSendTo,
169 SocketReceive,
170 SocketReceiveFrom,
171 FileRead,
172 FileWrite,
173 FileSend,
174 FileReadiness,
175 ExternalCompletion,
176 FileSystemOperation,
177 };
178
181 AsyncRequest(Type type) : state(State::Free), type(type), flags(0), unused(0), userFlags(0) {}
182
190 Result stop(AsyncEventLoop& eventLoop, Function<void(AsyncResult&)>* afterStopped = nullptr);
191
193 [[nodiscard]] bool isFree() const;
194
196 [[nodiscard]] bool isCancelling() const;
197
199 [[nodiscard]] bool isActive() const;
200
202 [[nodiscard]] Type getType() const { return type; }
203
205 Result start(AsyncEventLoop& eventLoop);
206
208 void setUserFlags(uint16_t externalFlags) { userFlags = externalFlags; }
209
211 uint16_t getUserFlags() const { return userFlags; }
212
214 [[nodiscard]] Function<void(AsyncResult&)>* getCloseCallback() { return closeCallback; }
215
216 [[nodiscard]] const Function<void(AsyncResult&)>* getCloseCallback() const { return closeCallback; }
217
218 protected:
219 Result checkState();
220
221 void queueSubmission(AsyncEventLoop& eventLoop);
222
223 AsyncSequence* sequence = nullptr;
224
225 AsyncTaskSequence* getTask();
226
227 [[nodiscard]] bool isThreadPoolForced() const;
228
229 private:
230 Function<void(AsyncResult&)>* closeCallback = nullptr;
231
232 friend struct AsyncEventLoop;
233 friend struct AsyncResult;
234
235 void markAsFree();
236
237 [[nodiscard]] static const char* TypeToString(Type type);
238 enum class State : uint8_t
239 {
240 Free, // not in any queue, this can be started with an async.start(...)
241 Setup, // when in submission queue waiting to be setup (after an async.start(...))
242 Submitting, // when in submission queue waiting to be activated or re-activated
243 Active, // when monitored by OS syscall or in activeLoopWakeUps / activeTimeouts queues
244 Reactivate, // when flagged for reactivation inside the callback (after a result.reactivateRequest(true))
245 Cancelling, // when in cancellation queue waiting for a cancelAsync (on active async)
246 };
247
248#if SC_ASYNC_ENABLE_LOG
249 const char* debugName = "None";
250#endif
251 State state; // 1 byte
252 Type type; // 1 byte
253 int16_t flags; // 2 bytes
254
255 uint16_t unused; // 2 bytes
256 uint16_t userFlags; // 2 bytes
257};
258
263struct SC_ASYNC_EXPORT AsyncSequence
264{
265 AsyncSequence* next = nullptr;
266 AsyncSequence* prev = nullptr;
267
268 bool clearSequenceOnCancel = true;
269 bool clearSequenceOnError = true;
270 private:
271 friend struct AsyncEventLoop;
272 bool runningAsync = false; // true if an async from this sequence is being run
273 bool tracked = false;
274
275 AsyncRequest* runningRequest = nullptr;
276
277 IntrusiveDoubleLinkedList<AsyncRequest> submissions;
278};
279
281struct SC_ASYNC_EXPORT AsyncCompletionData
282{
283};
284
287struct SC_ASYNC_EXPORT AsyncResult
288{
290 AsyncResult(AsyncEventLoop& eventLoop, AsyncRequest& request, SC::Result& res, bool* hasBeenReactivated = nullptr)
291 : eventLoop(eventLoop), async(request), hasBeenReactivated(hasBeenReactivated), returnCode(res)
292 {}
293
296 void reactivateRequest(bool shouldBeReactivated);
297
299 [[nodiscard]] const SC::Result& isValid() const { return returnCode; }
300
301 AsyncEventLoop& eventLoop;
302 AsyncRequest& async;
303
304 protected:
305 friend struct AsyncEventLoop;
306
307 bool shouldCallCallback = true;
308 bool* hasBeenReactivated = nullptr;
309
310 SC::Result& returnCode;
311};
312
316template <typename T, typename C>
318{
319 T& getAsync() { return static_cast<T&>(AsyncResult::async); }
320 const T& getAsync() const { return static_cast<const T&>(AsyncResult::async); }
321
323
324 C completionData;
325 int32_t eventIndex = 0;
326};
327
332struct SC_ASYNC_EXPORT AsyncLoopTimeout : public AsyncRequest
333{
334 AsyncLoopTimeout() : AsyncRequest(Type::LoopTimeout) {}
335
338 using AsyncRequest::start;
339
341 SC::Result start(AsyncEventLoop& eventLoop, TimeMs relativeTimeout);
342
346 SC::Result unschedule(AsyncEventLoop& eventLoop);
347
348 Function<void(Result&)> callback;
349
351
353 TimeMs getExpirationTime() const { return expirationTime; }
354
355 private:
356 SC::Result validate(AsyncEventLoop&);
357 friend struct AsyncEventLoop;
358 TimeMs expirationTime;
359};
360
363{
366 bool coalesce = true;
367};
368
389struct SC_ASYNC_EXPORT AsyncLoopWakeUp : public AsyncRequest
390{
391 AsyncLoopWakeUp() : AsyncRequest(Type::LoopWakeUp) {}
392
394 {
395 uint32_t deliveryCount = 1;
396 };
397
399
401 SC::Result start(AsyncEventLoop& eventLoop, AsyncLoopWakeUpOptions options = {});
402
404 SC::Result start(AsyncEventLoop& eventLoop, EventObject& eventObject, AsyncLoopWakeUpOptions options = {});
405
407 SC::Result wakeUp(AsyncEventLoop& eventLoop);
408
409 Function<void(Result&)> callback;
410 EventObject* eventObject = nullptr;
411
412 private:
413 friend struct AsyncEventLoop;
414 SC::Result validate(AsyncEventLoop&);
415 int32_t consumePendingWakeUps();
416 int32_t getPendingWakeUps() const;
417
418 AsyncLoopWakeUpOptions wakeUpOptions;
419 Atomic<int32_t> pendingWakeUps = 0;
420};
421
430struct SC_ASYNC_EXPORT AsyncProcessExit : public AsyncRequest
431{
432 AsyncProcessExit() : AsyncRequest(Type::ProcessExit) {}
433
435 {
436 int exitStatus;
437 };
438
439 struct Result : public AsyncResultOf<AsyncProcessExit, CompletionData>
440 {
441 using AsyncResultOf<AsyncProcessExit, CompletionData>::AsyncResultOf;
442
443 SC::Result get(int& status)
444 {
445 status = completionData.exitStatus;
446 return returnCode;
447 }
448 };
449 using AsyncRequest::start;
450
454 SC::Result start(AsyncEventLoop& eventLoop, FileDescriptor::Handle process);
455
456 Function<void(Result&)> callback;
457
458 private:
459 friend struct AsyncEventLoop;
460 SC::Result validate(AsyncEventLoop&);
461
462 FileDescriptor::Handle handle = FileDescriptor::Invalid;
463#if SC_PLATFORM_WINDOWS
464 detail::WinOverlappedOpaque overlapped;
465 detail::WinWaitHandle waitHandle;
466 AsyncEventLoop* eventLoop = nullptr;
467#elif SC_PLATFORM_LINUX
468 FileDescriptor pidFd;
469#endif
470};
471
474{
479 enum class Mode : uint8_t
480 {
481 Persistent,
482 OneShot
483 };
485 bool coalesce = true;
486};
487
507struct SC_ASYNC_EXPORT AsyncSignal : public AsyncRequest
508{
509 AsyncSignal() : AsyncRequest(Type::Signal) {}
510
512 {
513 int signalNumber = 0;
514 uint32_t deliveryCount = 1;
515 };
516
517 struct Result : public AsyncResultOf<AsyncSignal, CompletionData>
518 {
519 using AsyncResultOf<AsyncSignal, CompletionData>::AsyncResultOf;
520 };
521 using AsyncRequest::start;
522
524 SC::Result start(AsyncEventLoop& eventLoop, int num, AsyncSignalOptions options = {});
525
526 Function<void(Result&)> callback;
527
528 private:
529 friend struct AsyncEventLoop;
530 SC::Result validate(AsyncEventLoop&);
531
532 int signalNumber = 0;
533 AsyncSignalOptions signalOptions;
534#if SC_PLATFORM_WINDOWS
535 detail::WinOverlappedOpaque overlapped;
536 AsyncEventLoop* eventLoop = nullptr;
537#elif SC_PLATFORM_LINUX
538 FileDescriptor signalFd;
539 FileDescriptor::Handle signalFdHandle = FileDescriptor::Invalid;
540#endif
541};
542
543struct AsyncSocketAccept;
544namespace detail
545{
548struct SC_ASYNC_EXPORT AsyncSocketAcceptData
549{
550#if SC_PLATFORM_WINDOWS
551 void (*pAcceptEx)() = nullptr;
552 detail::WinOverlappedOpaque overlapped;
553 SocketDescriptor clientSocket;
554 uint8_t acceptBuffer[288] = {0};
555#elif SC_PLATFORM_LINUX
556 AlignedStorage<128> sockAddrHandle;
557 uint32_t sockAddrLen;
558#endif
559};
560
562struct SC_ASYNC_EXPORT AsyncSocketAcceptBase : public AsyncRequest
563{
564 AsyncSocketAcceptBase() : AsyncRequest(Type::SocketAccept) {}
565
566 struct CompletionData : public AsyncCompletionData
567 {
568 SocketDescriptor acceptedClient;
569 };
570
571 struct Result : public AsyncResultOf<AsyncSocketAccept, CompletionData>
572 {
573 using AsyncResultOf<AsyncSocketAccept, CompletionData>::AsyncResultOf;
574
575 SC::Result moveTo(SocketDescriptor& client)
576 {
577 SC_TRY(returnCode);
578 return SC::Result(client.assign(move(completionData.acceptedClient)));
579 }
580 };
581 using AsyncRequest::start;
582
584 SC::Result start(AsyncEventLoop& eventLoop, const SocketDescriptor& socketDescriptor, AsyncSocketAcceptData& data);
585 SC::Result validate(AsyncEventLoop&);
586
587 Function<void(Result&)> callback;
588 SocketDescriptor::Handle handle = SocketDescriptor::Invalid;
589 SocketFlags::AddressFamily addressFamily = SocketFlags::AddressFamilyIPV4;
590 AsyncSocketAcceptData* acceptData = nullptr;
591};
592
593} // namespace detail
594
604struct SC_ASYNC_EXPORT AsyncSocketAccept : public detail::AsyncSocketAcceptBase
605{
606 AsyncSocketAccept() { AsyncSocketAcceptBase::acceptData = &data; }
607 using AsyncSocketAcceptBase::start;
608
610 SC::Result start(AsyncEventLoop& eventLoop, const SocketDescriptor& socketDescriptor);
611
612 private:
613 detail::AsyncSocketAcceptData data;
614};
615
624struct SC_ASYNC_EXPORT AsyncSocketConnect : public AsyncRequest
625{
626 AsyncSocketConnect() : AsyncRequest(Type::SocketConnect) {}
627
630 using AsyncRequest::start;
631
633 SC::Result start(AsyncEventLoop& eventLoop, const SocketDescriptor& descriptor, SocketIPAddress address);
634 SC::Result start(AsyncEventLoop& eventLoop, const SocketDescriptor& descriptor, SocketAddress address);
635
636 Function<void(Result&)> callback;
637
638 SocketDescriptor::Handle handle = SocketDescriptor::Invalid;
639 SocketAddress address;
640
641 private:
642 friend struct AsyncEventLoop;
643 SC::Result validate(AsyncEventLoop&);
644
645#if SC_PLATFORM_WINDOWS
646 void (*pConnectEx)() = nullptr;
647 detail::WinOverlappedOpaque overlapped;
648#endif
649};
650
659struct SC_ASYNC_EXPORT AsyncSocketSend : public AsyncRequest
660{
661 AsyncSocketSend() : AsyncRequest(Type::SocketSend) {}
663 {
664 size_t numBytes = 0;
665 };
667 using AsyncRequest::start;
668
670 SC::Result start(AsyncEventLoop& eventLoop, const SocketDescriptor& descriptor, Span<const char> data);
671
673 SC::Result start(AsyncEventLoop& eventLoop, const SocketDescriptor& descriptor, Span<Span<const char>> data);
674
675 Function<void(Result&)> callback;
676
677 SocketDescriptor::Handle handle = SocketDescriptor::Invalid;
678
679 SC::Result closeHandle() { return detail::SocketDescriptorDefinition::releaseHandle(handle); }
680
681 Span<const char> buffer;
682 Span<Span<const char>> buffers;
683 bool singleBuffer = true;
684
685 protected:
686 AsyncSocketSend(Type type) : AsyncRequest(type) {}
687 friend struct AsyncEventLoop;
688 SC::Result validate(AsyncEventLoop&);
689
690 size_t totalBytesWritten = 0;
691#if SC_PLATFORM_WINDOWS
692 detail::WinOverlappedOpaque overlapped;
693#endif
694};
695
705struct SC_ASYNC_EXPORT AsyncSocketSendTo : public AsyncSocketSend
706{
707 AsyncSocketSendTo() : AsyncSocketSend(Type::SocketSendTo) {}
708
709 SocketAddress address;
710
711 SC::Result start(AsyncEventLoop& eventLoop, const SocketDescriptor& descriptor, SocketIPAddress ipAddress,
712 Span<const char> data);
713
714 SC::Result start(AsyncEventLoop& eventLoop, const SocketDescriptor& descriptor, SocketIPAddress ipAddress,
715 Span<Span<const char>> data);
716
717 SC::Result start(AsyncEventLoop& eventLoop, const SocketDescriptor& descriptor, SocketAddress socketAddress,
718 Span<const char> data);
719
720 SC::Result start(AsyncEventLoop& eventLoop, const SocketDescriptor& descriptor, SocketAddress socketAddress,
721 Span<Span<const char>> data);
722
723 private:
724 using AsyncSocketSend::start;
725 friend struct AsyncEventLoop;
726 SC::Result validate(AsyncEventLoop&);
727#if SC_PLATFORM_LINUX
728 AlignedStorage<56> typeErasedMsgHdr;
729#endif
730};
731
743struct SC_ASYNC_EXPORT AsyncSocketReceive : public AsyncRequest
744{
745 AsyncSocketReceive() : AsyncRequest(Type::SocketReceive) {}
746
748 {
749 size_t numBytes = 0;
750 bool disconnected = false;
751 bool truncated = false;
752 };
753
754 struct Result : public AsyncResultOf<AsyncSocketReceive, CompletionData>
755 {
756 using AsyncResultOf<AsyncSocketReceive, CompletionData>::AsyncResultOf;
757
758 bool isEnded() const { return completionData.disconnected; }
759
760 bool isTruncated() const { return completionData.truncated; }
761
765 SC::Result get(Span<char>& outData)
766 {
767 SC_TRY(getAsync().buffer.sliceStartLength(0, completionData.numBytes, outData));
768 return returnCode;
769 }
770
774
777 };
778 using AsyncRequest::start;
779
781 SC::Result start(AsyncEventLoop& eventLoop, const SocketDescriptor& descriptor, Span<char> data);
782
783 Function<void(Result&)> callback;
784
785 Span<char> buffer;
786 SocketDescriptor::Handle handle = SocketDescriptor::Invalid;
787
788 SC::Result closeHandle() { return detail::SocketDescriptorDefinition::releaseHandle(handle); }
789
790 protected:
791 AsyncSocketReceive(Type type) : AsyncRequest(type) {}
792 friend struct AsyncEventLoop;
793 SC::Result validate(AsyncEventLoop&);
794#if SC_PLATFORM_WINDOWS
795 detail::WinOverlappedOpaque overlapped;
796#endif
797};
798
808struct SC_ASYNC_EXPORT AsyncSocketReceiveFrom : public AsyncSocketReceive
809{
810 AsyncSocketReceiveFrom() : AsyncSocketReceive(Type::SocketReceiveFrom) {}
811 using AsyncSocketReceive::start;
812
813 private:
814 SocketAddress address;
815 friend struct AsyncSocketReceive;
816 friend struct AsyncEventLoop;
817#if SC_PLATFORM_LINUX
818 AlignedStorage<56> typeErasedMsgHdr;
819#elif SC_PLATFORM_WINDOWS
820 unsigned long receiveFlags = 0;
821 int addressSize = 0;
822 bool truncatedSync = false;
823#endif
824};
825
848struct SC_ASYNC_EXPORT AsyncFileRead : public AsyncRequest
849{
850 AsyncFileRead() : AsyncRequest(Type::FileRead) { handle = FileDescriptor::Invalid; }
851
853 {
854 size_t numBytes = 0;
855 bool endOfFile = false;
856 };
857
858 struct Result : public AsyncResultOf<AsyncFileRead, CompletionData>
859 {
860 using AsyncResultOf<AsyncFileRead, CompletionData>::AsyncResultOf;
861
862 bool isEnded() const { return completionData.endOfFile; }
863
864 SC::Result get(Span<char>& data)
865 {
866 SC_TRY(getAsync().buffer.sliceStartLength(0, completionData.numBytes, data));
867 return returnCode;
868 }
869 };
870 using AsyncRequest::start;
871
873 SC::Result start(AsyncEventLoop& eventLoop, const FileDescriptor& descriptor, Span<char> data);
874
875 Function<void(Result&)> callback;
876 Span<char> buffer;
877 FileDescriptor::Handle handle;
879
880 SC::Result closeHandle() { return detail::FileDescriptorDefinition::releaseHandle(handle); }
881
883 uint64_t getOffset() const { return offset; }
884
887 void setOffset(uint64_t fileOffset)
888 {
889 useOffset = true;
890 offset = fileOffset;
891 }
892
893 private:
894 friend struct AsyncEventLoop;
895 SC::Result validate(AsyncEventLoop&);
896
897 bool useOffset = false;
898 bool endedSync = false;
899
900 uint64_t offset = 0;
901#if SC_PLATFORM_WINDOWS
902 uint64_t readCursor = 0;
903 detail::WinOverlappedOpaque overlapped;
904#endif
905};
906
928struct SC_ASYNC_EXPORT AsyncFileWrite : public AsyncRequest
929{
930 AsyncFileWrite() : AsyncRequest(Type::FileWrite) { handle = FileDescriptor::Invalid; }
931
933 {
934 size_t numBytes = 0;
935 };
936
937 struct Result : public AsyncResultOf<AsyncFileWrite, CompletionData>
938 {
939 using AsyncResultOf<AsyncFileWrite, CompletionData>::AsyncResultOf;
940
941 SC::Result get(size_t& writtenSizeInBytes)
942 {
943 writtenSizeInBytes = completionData.numBytes;
944 return returnCode;
945 }
946 };
947
948 using AsyncRequest::start;
949
951 SC::Result start(AsyncEventLoop& eventLoop, const FileDescriptor& descriptor, Span<Span<const char>> data);
952
954 SC::Result start(AsyncEventLoop& eventLoop, Span<Span<const char>> data);
955
957 SC::Result start(AsyncEventLoop& eventLoop, const FileDescriptor& descriptor, Span<const char> data);
958
960 SC::Result start(AsyncEventLoop& eventLoop, Span<const char> data);
961
962 Function<void(Result&)> callback;
963
964 FileDescriptor::Handle handle;
966
967 SC::Result closeHandle() { return detail::FileDescriptorDefinition::releaseHandle(handle); }
968
969 Span<const char> buffer;
970 Span<Span<const char>> buffers;
971 bool singleBuffer = true;
972
974 uint64_t getOffset() const { return offset; }
975
978 void setOffset(uint64_t fileOffset)
979 {
980 useOffset = true;
981 offset = fileOffset;
982 }
983
984 private:
985 friend struct AsyncEventLoop;
986 SC::Result validate(AsyncEventLoop&);
987
988#if SC_PLATFORM_WINDOWS
989 bool endedSync = false;
990#else
991 bool isWatchable = false;
992#endif
993 bool useOffset = false;
994 uint64_t offset = 0xffffffffffffffff;
995
996 size_t totalBytesWritten = 0;
997#if SC_PLATFORM_WINDOWS
998 detail::WinOverlappedOpaque overlapped;
999#endif
1000};
1001
1005struct SC_ASYNC_EXPORT AsyncFileReadiness : public AsyncRequest
1006{
1007 AsyncFileReadiness() : AsyncRequest(Type::FileReadiness) {}
1008
1011
1013 SC::Result start(AsyncEventLoop& eventLoop, FileDescriptor::Handle fileDescriptor);
1014
1015 Function<void(Result&)> callback;
1016
1017 private:
1018 friend struct AsyncEventLoop;
1019 SC::Result validate(AsyncEventLoop&);
1020
1021 FileDescriptor::Handle handle = FileDescriptor::Invalid;
1022};
1023
1027struct SC_ASYNC_EXPORT AsyncExternalCompletion : public AsyncRequest
1028{
1030 {
1031 size_t bytesTransferred = 0;
1032 };
1034
1035 AsyncExternalCompletion() : AsyncRequest(Type::ExternalCompletion) {}
1036
1038 SC::Result start(AsyncEventLoop& eventLoop);
1039
1040#if SC_PLATFORM_WINDOWS
1042 SC::Result start(AsyncEventLoop& eventLoop, FileDescriptor::Handle fileDescriptor);
1043
1045 [[nodiscard]] void* getWindowsOverlapped();
1046#endif
1047
1050
1053
1054 [[nodiscard]] bool hasSubmissionPending() const { return submissionPending; }
1055
1056 Function<void(Result&)> callback;
1057
1058 private:
1059 friend struct AsyncEventLoop;
1060 SC::Result validate(AsyncEventLoop&);
1061
1062 FileDescriptor::Handle handle = FileDescriptor::Invalid;
1063 size_t bytesTransferred = 0;
1064 bool manualMode = true;
1065 bool submissionPending = false;
1066 bool completionPosted = false;
1067#if SC_PLATFORM_WINDOWS
1068 detail::WinOverlappedOpaque overlapped;
1069#endif
1070};
1071
1096struct SC_ASYNC_EXPORT AsyncFileSend : public AsyncRequest
1097{
1098 AsyncFileSend() : AsyncRequest(Type::FileSend) {}
1099
1101 {
1102 size_t bytesTransferred = 0;
1103 bool usedZeroCopy = false;
1104 };
1105
1106 struct Result : public AsyncResultOf<AsyncFileSend, CompletionData>
1107 {
1108 using AsyncResultOf<AsyncFileSend, CompletionData>::AsyncResultOf;
1109
1111 [[nodiscard]] size_t getBytesTransferred() const { return completionData.bytesTransferred; }
1112
1114 [[nodiscard]] bool usedZeroCopy() const { return completionData.usedZeroCopy; }
1115
1117 [[nodiscard]] bool isComplete() const
1118 {
1119 return returnCode && completionData.bytesTransferred == getAsync().length;
1120 }
1121 };
1122
1123 using AsyncRequest::start;
1124
1134 SC::Result start(AsyncEventLoop& eventLoop, const FileDescriptor& file, const SocketDescriptor& socket,
1135 int64_t offset = 0, size_t length = 0, size_t pipeSize = 0);
1136
1137 Function<void(Result&)> callback;
1138
1139 // Internal handles (set by start())
1140 FileDescriptor::Handle fileHandle = FileDescriptor::Invalid;
1141 SocketDescriptor::Handle socketHandle = SocketDescriptor::Invalid;
1142
1143 int64_t offset = 0;
1144 size_t length = 0;
1145 size_t bytesSent = 0;
1146 private:
1147 friend struct AsyncEventLoop;
1148 SC::Result validate(AsyncEventLoop&);
1149
1150#if SC_PLATFORM_WINDOWS
1151 detail::WinOverlappedOpaque overlapped;
1152#elif SC_PLATFORM_LINUX
1153 size_t pipeBufferSize = 0;
1154 PipeDescriptor splicePipe;
1155 size_t spliceBytesPending = 0;
1156#endif
1157};
1158
1159// forward declared because it must be defined after AsyncTaskSequence
1160struct AsyncLoopWork;
1162
1164{
1165 FileDescriptor::Handle handle = FileDescriptor::Invalid; // for open
1166
1167 int code = 0; // for open/close
1168 size_t numBytes = 0; // for read
1169};
1170
1171namespace detail
1172{
1173// A simple hand-made variant of all completion types
1174struct SC_ASYNC_EXPORT AsyncCompletionVariant
1175{
1176 AsyncCompletionVariant() {}
1177 ~AsyncCompletionVariant() { destroy(); }
1178
1179 AsyncCompletionVariant(const AsyncCompletionVariant&) = delete;
1180 AsyncCompletionVariant(AsyncCompletionVariant&&) = delete;
1181 AsyncCompletionVariant& operator=(const AsyncCompletionVariant&) = delete;
1182 AsyncCompletionVariant& operator=(AsyncCompletionVariant&&) = delete;
1183
1184 bool inited = false;
1185
1186 AsyncRequest::Type type;
1187 union
1188 {
1189 AsyncCompletionData completionDataLoopWork; // Defined after AsyncCompletionVariant / AsyncTaskSequence
1190 AsyncLoopTimeout::CompletionData completionDataLoopTimeout;
1191 AsyncLoopWakeUp::CompletionData completionDataLoopWakeUp;
1192 AsyncProcessExit::CompletionData completionDataProcessExit;
1193 AsyncSignal::CompletionData completionDataSignal;
1194 AsyncSocketAccept::CompletionData completionDataSocketAccept;
1195 AsyncSocketConnect::CompletionData completionDataSocketConnect;
1196 AsyncSocketSend::CompletionData completionDataSocketSend;
1197 AsyncSocketSendTo::CompletionData completionDataSocketSendTo;
1198 AsyncSocketReceive::CompletionData completionDataSocketReceive;
1199 AsyncSocketReceiveFrom::CompletionData completionDataSocketReceiveFrom;
1200 AsyncFileRead::CompletionData completionDataFileRead;
1201 AsyncFileWrite::CompletionData completionDataFileWrite;
1202 AsyncFileSend::CompletionData completionDataFileSend;
1203 AsyncFileReadiness::CompletionData completionDataFileReadiness;
1204 AsyncExternalCompletion::CompletionData completionDataExternalCompletion;
1205
1206 AsyncFileSystemOperationCompletionData completionDataFileSystemOperation;
1207 };
1208
1209 auto& getCompletion(AsyncLoopWork&) { return completionDataLoopWork; }
1210 auto& getCompletion(AsyncLoopTimeout&) { return completionDataLoopTimeout; }
1211 auto& getCompletion(AsyncLoopWakeUp&) { return completionDataLoopWakeUp; }
1212 auto& getCompletion(AsyncProcessExit&) { return completionDataProcessExit; }
1213 auto& getCompletion(AsyncSignal&) { return completionDataSignal; }
1214 auto& getCompletion(AsyncSocketAccept&) { return completionDataSocketAccept; }
1215 auto& getCompletion(AsyncSocketConnect&) { return completionDataSocketConnect; }
1216 auto& getCompletion(AsyncSocketSend&) { return completionDataSocketSend; }
1217 auto& getCompletion(AsyncSocketReceive&) { return completionDataSocketReceive; }
1218 auto& getCompletion(AsyncFileRead&) { return completionDataFileRead; }
1219 auto& getCompletion(AsyncFileWrite&) { return completionDataFileWrite; }
1220 auto& getCompletion(AsyncFileSend&) { return completionDataFileSend; }
1221 auto& getCompletion(AsyncFileReadiness&) { return completionDataFileReadiness; }
1222 auto& getCompletion(AsyncExternalCompletion&) { return completionDataExternalCompletion; }
1223 auto& getCompletion(AsyncFileSystemOperation&) { return completionDataFileSystemOperation; }
1224
1225 template <typename T>
1226 auto& construct(T& t)
1227 {
1228 destroy();
1229 placementNew(getCompletion(t));
1230 inited = true;
1231 type = t.getType();
1232 return getCompletion(t);
1233 }
1234 void destroy();
1235};
1236} // namespace detail
1237
1241struct SC_ASYNC_EXPORT AsyncTaskSequence : public AsyncSequence
1242{
1243 protected:
1244 ThreadPoolTask task;
1245 ThreadPool* threadPool = nullptr;
1246
1247 friend struct AsyncEventLoop;
1248 friend struct AsyncRequest;
1249
1250 detail::AsyncCompletionVariant completion;
1251
1252 SC::Result returnCode = SC::Result(true);
1253};
1254
1260struct SC_ASYNC_EXPORT AsyncLoopWork : public AsyncRequest
1261{
1262 AsyncLoopWork() : AsyncRequest(Type::LoopWork) {}
1263
1266
1269 SC::Result setThreadPool(ThreadPool& threadPool, AsyncThreadPoolMode mode = AsyncThreadPoolMode::NativePreferred);
1270
1271 Function<SC::Result()> work;
1272 Function<void(Result&)> callback;
1273
1274 private:
1275 friend struct AsyncEventLoop;
1276 SC::Result validate(AsyncEventLoop&);
1277 AsyncTaskSequence task;
1278};
1279
1313struct SC_ASYNC_EXPORT AsyncFileSystemOperation : public AsyncRequest
1314{
1315 AsyncFileSystemOperation() : AsyncRequest(Type::FileSystemOperation) {}
1316 ~AsyncFileSystemOperation() { destroy(); }
1317#ifdef CopyFile
1318#undef CopyFile
1319#endif
1320#ifdef RemoveDirectory
1321#undef RemoveDirectory
1322#endif
1323 enum class Operation
1324 {
1325 None = 0,
1326 Open,
1327 Close,
1328 Read,
1329 Write,
1330 CopyFile,
1331 CopyDirectory,
1332 Rename,
1333 RemoveDirectory,
1334 RemoveFile,
1335 };
1336
1339
1341 SC::Result setThreadPool(ThreadPool& threadPool, AsyncThreadPoolMode mode = AsyncThreadPoolMode::NativePreferred);
1342
1344 SC::Result stop(AsyncEventLoop& eventLoop, Function<void(AsyncResult&)>* afterStopped = nullptr);
1345
1346 Function<void(Result&)> callback;
1347
1353 SC::Result open(AsyncEventLoop& eventLoop, StringSpan path, FileOpen mode);
1354
1359 SC::Result close(AsyncEventLoop& eventLoop, FileDescriptor::Handle handle);
1360
1367 SC::Result read(AsyncEventLoop& eventLoop, FileDescriptor::Handle handle, Span<char> buffer, uint64_t offset);
1368
1375 SC::Result write(AsyncEventLoop& eventLoop, FileDescriptor::Handle handle, Span<const char> buffer,
1376 uint64_t offset);
1377
1384 SC::Result copyFile(AsyncEventLoop& eventLoop, StringSpan path, StringSpan destinationPath,
1386
1393 SC::Result copyDirectory(AsyncEventLoop& eventLoop, StringSpan path, StringSpan destinationPath,
1395
1401 SC::Result rename(AsyncEventLoop& eventLoop, StringSpan path, StringSpan newPath);
1402
1408 SC::Result removeEmptyDirectory(AsyncEventLoop& eventLoop, StringSpan path);
1409
1414 SC::Result removeFile(AsyncEventLoop& eventLoop, StringSpan path);
1415
1416 private:
1417 friend struct AsyncEventLoop;
1418 Operation operation = Operation::None;
1419 AsyncThreadPoolMode threadPoolMode = AsyncThreadPoolMode::NativePreferred;
1420 AsyncLoopWork loopWork;
1421 CompletionData completionData;
1422
1423 void onOperationCompleted(AsyncLoopWork::Result& res);
1424
1425 struct FileDescriptorData
1426 {
1427 FileDescriptor::Handle handle;
1428 };
1429
1430 struct OpenData
1431 {
1432 StringSpan path;
1433 FileOpen mode;
1434 };
1435
1436 struct ReadData
1437 {
1438 FileDescriptor::Handle handle;
1439 Span<char> buffer;
1440 uint64_t offset;
1441 };
1442
1443 struct WriteData
1444 {
1445 FileDescriptor::Handle handle;
1446 Span<const char> buffer;
1447 uint64_t offset;
1448 };
1449
1450 struct CopyFileData
1451 {
1452 StringSpan path;
1453 StringSpan destinationPath;
1454 FileSystemCopyFlags copyFlags;
1455 };
1456
1457 using CopyDirectoryData = CopyFileData;
1458
1459 using CloseData = FileDescriptorData;
1460
1461 struct RenameData
1462 {
1463 StringSpan path;
1464 StringSpan newPath;
1465 };
1466
1467 struct RemoveData
1468 {
1469 StringSpan path;
1470 };
1471
1472 union
1473 {
1474 OpenData openData;
1475 CloseData closeData;
1476 ReadData readData;
1477 WriteData writeData;
1478 CopyFileData copyFileData;
1479 CopyDirectoryData copyDirectoryData;
1480 RenameData renameData;
1481 RemoveData removeData;
1482 };
1483
1484 void destroy();
1485
1486 SC::Result start(AsyncEventLoop& eventLoop, FileDescriptor::Handle fileDescriptor);
1487 SC::Result validate(AsyncEventLoop&);
1488};
1489
1493struct SC_ASYNC_EXPORT AsyncKernelEvents
1494{
1495 Span<uint8_t> eventsMemory;
1496
1497 private:
1498 int numberOfEvents = 0;
1499 friend struct AsyncEventLoop;
1500 friend struct AsyncEventLoopMonitor;
1501};
1502
1504struct SC_ASYNC_EXPORT AsyncEventLoopListeners
1505{
1506 Function<void(AsyncEventLoop&)> beforeBlockingPoll;
1507 Function<void(AsyncEventLoop&)> afterBlockingPoll;
1508};
1509
1516struct SC_ASYNC_EXPORT AsyncEventLoop
1517{
1519 struct Options
1520 {
1521 enum class ApiType : uint8_t
1522 {
1523 Automatic = 0,
1524 ForceUseIoUring,
1525 ForceUseEpoll,
1526 };
1528
1529 Options() { apiType = ApiType::Automatic; }
1530 };
1531
1533
1534 AsyncEventLoop(const AsyncEventLoop&) = delete;
1535 AsyncEventLoop(AsyncEventLoop&&) = delete;
1536 AsyncEventLoop& operator=(AsyncEventLoop&&) = delete;
1537 AsyncEventLoop& operator=(const AsyncEventLoop&) = delete;
1538
1540 Result create(Options options = Options());
1541
1543 Result close();
1544
1547 Result start(AsyncRequest& async);
1548
1550 Result postExternalCompletion(AsyncExternalCompletion& async, size_t bytesTransferred = 0);
1551
1555
1557 [[nodiscard]] bool isInitialized() const;
1558
1560 [[nodiscard]] bool needsThreadPoolForFileOperations() const;
1561
1569 Result run();
1570
1580 Result runOnce();
1581
1587 Result runNoWait();
1588
1593 Result submitRequests(AsyncKernelEvents& kernelEvents);
1594
1615 Result blockingPoll(AsyncKernelEvents& kernelEvents);
1616
1624
1628
1631
1634
1637
1640 SocketFlags::ProtocolType protocol, SocketDescriptor& outDescriptor);
1641
1644
1646 Result associateExternallyCreatedSocketHandle(SocketDescriptor::Handle handle);
1647
1650
1652 Result associateExternallyCreatedFileDescriptorHandle(FileDescriptor::Handle handle);
1653
1655 static Result removeAllAssociationsFor(SocketDescriptor& outDescriptor);
1656
1658 static Result removeAllAssociationsForSocketHandle(SocketDescriptor::Handle handle);
1659
1661 static Result removeAllAssociationsFor(FileDescriptor& outDescriptor);
1662
1664 static Result removeAllAssociationsForFileDescriptorHandle(FileDescriptor::Handle handle);
1665
1668
1670 [[nodiscard]] TimeMs getLoopTime() const;
1671
1673 [[nodiscard]] int getNumberOfActiveRequests() const;
1674
1676 [[nodiscard]] int getNumberOfSubmittedRequests() const;
1677
1681
1686
1689
1694 void enumerateRequests(Function<void(AsyncRequest&)> enumerationCallback);
1695
1699
1701 [[nodiscard]] static bool isExcludedFromActiveCount(const AsyncRequest& async);
1702
1705 [[nodiscard]] static bool tryProbingIOUring();
1706
1709
1710 struct Internal;
1711
1713 using LoopWork = AsyncLoopWork;
1716 using Signal = AsyncSignal;
1723 using FileRead = AsyncFileRead;
1724 using FileWrite = AsyncFileWrite;
1725 using FileSend = AsyncFileSend;
1730 using ResultType = AsyncResult;
1731
1732 public:
1733 struct SC_ASYNC_EXPORT InternalDefinition
1734 {
1735 static constexpr int Windows = 576;
1736 static constexpr int Apple = 552;
1737 static constexpr int Linux = 816;
1738 static constexpr int Default = Linux;
1739
1740 static constexpr size_t Alignment = 8;
1741
1742 using Object = Internal;
1743 };
1744
1745 using InternalOpaque = OpaqueObject<InternalDefinition>;
1746
1747 private:
1748 InternalOpaque internalOpaque;
1749 Internal& internal;
1750
1751 friend struct AsyncRequest;
1752 friend struct AsyncLoopTimeout;
1753 friend struct AsyncFileWrite;
1754 friend struct AsyncFileRead;
1755 friend struct AsyncFileSystemOperation;
1756 friend struct AsyncResult;
1757};
1758
1762struct SC_ASYNC_EXPORT AsyncEventLoopMonitor
1763{
1764 Function<void(void)> onNewEventsAvailable;
1765
1768 Result create(AsyncEventLoop& eventLoop);
1769
1771 Result close();
1772
1780
1786
1787 private:
1788#if SC_COMPILER_MSVC
1789#pragma warning(push)
1790#pragma warning(disable : 4324) // useless warning on 32 bit... (structure was padded due to __declspec(align()))
1791#endif
1792 alignas(uint64_t) uint8_t eventsMemory[8 * 1024]; // 8 Kb of kernel events
1793#if SC_COMPILER_MSVC
1794#pragma warning(pop)
1795#endif
1796
1797 AsyncKernelEvents asyncKernelEvents;
1798 AsyncEventLoop* eventLoop = nullptr;
1799 AsyncLoopWakeUp eventLoopWakeUp;
1800
1801 Thread eventLoopThread;
1802 EventObject eventObjectEnterBlockingMode;
1803 EventObject eventObjectExitBlockingMode;
1804
1805 Atomic<bool> finished = false;
1806 Atomic<bool> needsWakeUp = true;
1807
1808 bool wakeUpHasBeenCalled = false;
1809
1810 Result monitoringLoopThread(Thread& thread);
1811};
1812
1813} // namespace SC
Empty base struct for all AsyncRequest-derived CompletionData (internal) structs.
Definition Async.h:282
Allow library user to provide callbacks signaling different phases of async event loop cycle.
Definition Async.h:1505
Monitors Async I/O events from a background thread using a blocking kernel function (no CPU usage on ...
Definition Async.h:1763
Function< void(void)> onNewEventsAvailable
Informs to call dispatchCompletions on GUI Event Loop.
Definition Async.h:1764
Result startMonitoring()
Queue all async requests submissions and start monitoring loop events on a background thread.
Result close()
Stop monitoring the AsyncEventLoop, disposing all resources.
Result stopMonitoringAndDispatchCompletions()
Stops monitoring events on the background thread and dispatches callbacks for completed requests.
Result create(AsyncEventLoop &eventLoop)
Create the monitoring thread for an AsyncEventLoop.
Options given to AsyncEventLoop::create.
Definition Async.h:1520
ApiType apiType
Criteria to choose Async IO API.
Definition Async.h:1527
ApiType
Definition Async.h:1522
Asynchronous I/O (files, sockets, timers, processes, fs events, threads wake-up) (see Async) AsyncEve...
Definition Async.h:1517
bool needsThreadPoolForFileOperations() const
Returns true if backend needs a thread pool for non-blocking fs operations (anything but io_uring bas...
Result associateExternallyCreatedFileDescriptor(FileDescriptor &outDescriptor)
Associates a previously created File Descriptor with the eventLoop.
Result wakeUpFromExternalThread()
Wake up the event loop from a thread different than the one where run() is called (and potentially bl...
Result runNoWait()
Process ready requests if any, dispatching their completions, or returns immediately without blocking...
static Result removeAllAssociationsFor(SocketDescriptor &outDescriptor)
Removes association of a TCP Socket with any event loop.
void updateTime()
Updates loop time to "now".
static bool tryProbingIOUring()
Check if io_uring can be created directly (only on Linux)
static bool isExcludedFromActiveCount(const AsyncRequest &async)
Checks if excludeFromActiveCount() has been called on the given request.
Result associateExternallyCreatedSocket(SocketDescriptor &outDescriptor)
Associates a previously created TCP / UDP socket with the eventLoop.
Result associateExternallyCreatedFileDescriptorHandle(FileDescriptor::Handle handle)
Associates a previously created File Descriptor handle with the eventLoop.
Result blockingPoll(AsyncKernelEvents &kernelEvents)
Blocks until at least one event happens, ensuring forward progress, without executing completions.
void clearSequence(AsyncSequence &sequence)
Clears the sequence.
int getNumberOfSubmittedRequests() const
Obtain the total number of submitted requests.
Result submitRequests(AsyncKernelEvents &kernelEvents)
Submits all queued async requests without running user callbacks.
void enumerateRequests(Function< void(AsyncRequest &)> enumerationCallback)
Enumerates user-visible request objects associated with this loop.
Result postExternalCompletion(AsyncExternalCompletion &async, size_t bytesTransferred=0)
Posts completion for an AsyncExternalCompletion started in manual mode.
TimeMs getLoopTime() const
Get Loop time (monotonic)
Result associateExternallyCreatedSocketHandle(SocketDescriptor::Handle handle)
Associates a previously created TCP / UDP socket handle with the eventLoop.
Result start(AsyncRequest &async)
Queues an async request request that has been correctly setup.
Result createAsyncSocket(SocketFlags::AddressFamily family, SocketFlags::SocketType socketType, SocketFlags::ProtocolType protocol, SocketDescriptor &outDescriptor)
Creates a non-blocking socket registered with the event loop.
AsyncLoopTimeout * findEarliestLoopTimeout() const
Returns the next AsyncLoopTimeout that will be executed (shortest relativeTimeout)
void setListeners(AsyncEventLoopListeners *listeners)
Sets listeners invoked around AsyncEventLoop::blockingPoll.
Result dispatchCompletions(AsyncKernelEvents &kernelEvents)
Invokes completions for the AsyncKernelEvents collected by a call to AsyncEventLoop::blockingPoll.
void interrupt()
Interrupts AsyncEventLoop::run, causing it to return even if counted active work remains.
Result wakeUpFromExternalThread(AsyncLoopWakeUp &wakeUp)
Wake up the event loop from a thread different than the one where run() is called (and potentially bl...
bool isInitialized() const
Returns true if create has been already called (successfully)
static Result removeAllAssociationsForSocketHandle(SocketDescriptor::Handle handle)
Removes association of a TCP Socket handle with any event loop.
Result create(Options options=Options())
Creates the event loop kernel object.
Result createAsyncTCPSocket(SocketFlags::AddressFamily family, SocketDescriptor &outDescriptor)
Creates an async TCP (IPV4 / IPV6) socket registered with the eventLoop.
Result close()
Closes the event loop kernel object.
static Result removeAllAssociationsForFileDescriptorHandle(FileDescriptor::Handle handle)
Removes association of a File Descriptor handle with any event loop.
Result createAsyncUDPSocket(SocketFlags::AddressFamily family, SocketDescriptor &outDescriptor)
Creates an async UCP (IPV4 / IPV6) socket registered with the eventLoop.
static Result removeAllAssociationsFor(FileDescriptor &outDescriptor)
Removes association of a File Descriptor with any event loop.
Result runOnce()
Blocks until at least one request proceeds, ensuring forward progress, dispatching ready completions.
void excludeFromActiveCount(AsyncRequest &async)
Excludes the request from active handles count so it does not keep AsyncEventLoop::run alive.
Result run()
Blocks until there are no more counted active, submitted, or cancelling requests, dispatching complet...
void includeInActiveCount(AsyncRequest &async)
Reverses the effect of excludeFromActiveCount for the request.
int getNumberOfActiveRequests() const
Obtain the total number of active requests.
Integrates externally-submitted completion based operations with AsyncEventLoop.
Definition Async.h:1028
SC::Result clearSubmissionPending()
Clears a pending submission after an external submission failed synchronously.
SC::Result start(AsyncEventLoop &eventLoop)
Starts a manual external completion. The request remains active until postExternalCompletion() or sto...
SC::Result markSubmissionPending()
Marks that a native/manual external operation has been submitted and must complete before reuse.
Definition Async.h:853
Definition Async.h:859
Starts a file read operation, reading bytes from a file (or pipe).
Definition Async.h:849
FileDescriptor::Handle handle
The writeable span of memory where to data will be written.
Definition Async.h:877
Span< char > buffer
Callback called when some data has been read from the file into the buffer.
Definition Async.h:876
SC::Result closeHandle()
The file/pipe descriptor handle to read data from.
Definition Async.h:880
void setOffset(uint64_t fileOffset)
Sets the offset in bytes at which start reading.
Definition Async.h:887
SC::Result start(AsyncEventLoop &eventLoop, const FileDescriptor &descriptor, Span< char > data)
Sets async request members and calls AsyncEventLoop::start.
uint64_t getOffset() const
Returns the last offset set with AsyncFileRead::setOffset.
Definition Async.h:883
Starts a file descriptor readiness operation.
Definition Async.h:1006
SC::Result start(AsyncEventLoop &eventLoop, FileDescriptor::Handle fileDescriptor)
Starts a file descriptor poll operation, monitoring its readiness with appropriate OS API.
Definition Async.h:1101
Definition Async.h:1107
size_t getBytesTransferred() const
Get the number of bytes transferred.
Definition Async.h:1111
bool usedZeroCopy() const
Check if zero-copy was used for this transfer.
Definition Async.h:1114
bool isComplete() const
Check if the entire requested range was sent.
Definition Async.h:1117
Sends file contents to a socket using zero-copy when available (sendfile, TransmitFile).
Definition Async.h:1097
Function< void(Result &)> callback
Called when send completes or fails.
Definition Async.h:1137
SC::Result start(AsyncEventLoop &eventLoop, const FileDescriptor &file, const SocketDescriptor &socket, int64_t offset=0, size_t length=0, size_t pipeSize=0)
Start file send.
Starts an asynchronous file system operation (open, close, read, write, sendFile, stat,...
Definition Async.h:1314
SC::Result stop(AsyncEventLoop &eventLoop, Function< void(AsyncResult &)> *afterStopped=nullptr)
Stops the operation, including the internal thread-pool work item when used.
SC::Result copyDirectory(AsyncEventLoop &eventLoop, StringSpan path, StringSpan destinationPath, FileSystemCopyFlags copyFlags=FileSystemCopyFlags())
Copies a directory from one location to another.
SC::Result removeEmptyDirectory(AsyncEventLoop &eventLoop, StringSpan path)
Removes a directory asynchronously.
SC::Result setThreadPool(ThreadPool &threadPool, AsyncThreadPoolMode mode=AsyncThreadPoolMode::NativePreferred)
Sets the thread pool to use for the operation.
SC::Result rename(AsyncEventLoop &eventLoop, StringSpan path, StringSpan newPath)
Renames a file.
SC::Result removeFile(AsyncEventLoop &eventLoop, StringSpan path)
Removes a file asynchronously.
SC::Result read(AsyncEventLoop &eventLoop, FileDescriptor::Handle handle, Span< char > buffer, uint64_t offset)
Reads data from a file descriptor at a given offset.
SC::Result write(AsyncEventLoop &eventLoop, FileDescriptor::Handle handle, Span< const char > buffer, uint64_t offset)
Writes data to a file descriptor at a given offset.
SC::Result close(AsyncEventLoop &eventLoop, FileDescriptor::Handle handle)
Closes a file descriptor asynchronously.
Function< void(Result &)> callback
Called after the operation is completed, on the event loop thread.
Definition Async.h:1346
SC::Result copyFile(AsyncEventLoop &eventLoop, StringSpan path, StringSpan destinationPath, FileSystemCopyFlags copyFlags=FileSystemCopyFlags())
Copies a file from one location to another.
SC::Result open(AsyncEventLoop &eventLoop, StringSpan path, FileOpen mode)
Opens a file asynchronously and returns its corresponding file descriptor.
Definition Async.h:938
Starts a file write operation, writing bytes to a file (or pipe).
Definition Async.h:929
uint64_t getOffset() const
Returns the last offset set with AsyncFileWrite::setOffset.
Definition Async.h:974
FileDescriptor::Handle handle
The file/pipe descriptor to write data to.
Definition Async.h:964
SC::Result start(AsyncEventLoop &eventLoop, Span< const char > data)
Sets async request members and calls AsyncEventLoop::start.
SC::Result start(AsyncEventLoop &eventLoop, const FileDescriptor &descriptor, Span< Span< const char > > data)
Sets async request members and calls AsyncEventLoop::start.
void setOffset(uint64_t fileOffset)
Sets the offset in bytes at which start writing.
Definition Async.h:978
Function< void(Result &)> callback
Callback called when descriptor is ready to be written with more data.
Definition Async.h:962
SC::Result start(AsyncEventLoop &eventLoop, const FileDescriptor &descriptor, Span< const char > data)
Sets async request members and calls AsyncEventLoop::start.
Span< Span< const char > > buffers
The read-only spans of memory where to read the data from.
Definition Async.h:970
SC::Result start(AsyncEventLoop &eventLoop, Span< Span< const char > > data)
Sets async request members and calls AsyncEventLoop::start.
Span< const char > buffer
The read-only span of memory where to read the data from.
Definition Async.h:969
Allows user to supply a block of memory that will store kernel I/O events retrieved from AsyncEventLo...
Definition Async.h:1494
Span< uint8_t > eventsMemory
User supplied block of memory used to store kernel I/O events.
Definition Async.h:1495
Starts a Timeout that is invoked only once after expiration (relative) time has passed.
Definition Async.h:333
TimeMs getExpirationTime() const
Gets computed absolute expiration time that determines when this timeout get executed.
Definition Async.h:353
SC::Result start(AsyncEventLoop &eventLoop, TimeMs relativeTimeout)
Sets async request members and calls AsyncEventLoop::start.
TimeMs relativeTimeout
First timer expiration (relative) time in milliseconds.
Definition Async.h:350
Function< void(Result &)> callback
Called after given expiration time since AsyncLoopTimeout::start has passed.
Definition Async.h:348
SC::Result unschedule(AsyncEventLoop &eventLoop)
Synchronously removes an unsequenced timeout from the event loop schedule without invoking its callba...
Options for AsyncLoopWakeUp configuration.
Definition Async.h:363
bool coalesce
Merge repeated pending wakeUp() calls into a single callback (default true, matching libuv uv_async_t...
Definition Async.h:366
Starts a wake-up operation, allowing threads to execute callbacks on loop thread.
Definition Async.h:390
SC::Result start(AsyncEventLoop &eventLoop, EventObject &eventObject, AsyncLoopWakeUpOptions options={})
Sets async request members and calls AsyncEventLoop::start.
Function< void(Result &)> callback
Callback called by SC::AsyncEventLoop::run after SC::AsyncLoopWakeUp::wakeUp.
Definition Async.h:409
SC::Result wakeUp(AsyncEventLoop &eventLoop)
Wakes up event loop, scheduling AsyncLoopWakeUp::callback on next AsyncEventLoop::run (or its variati...
SC::Result start(AsyncEventLoop &eventLoop, AsyncLoopWakeUpOptions options={})
Sets async request members and calls AsyncEventLoop::start.
Executes work in a thread pool and then invokes a callback on the event loop thread.
Definition Async.h:1261
Function< void(Result &)> callback
Called to execute the work in a background threadpool thread.
Definition Async.h:1272
SC::Result setThreadPool(ThreadPool &threadPool, AsyncThreadPoolMode mode=AsyncThreadPoolMode::NativePreferred)
Sets the ThreadPool that will supply the thread to run the async work on.
Definition Async.h:440
Waits for a child process to exit and reports its exit status.
Definition Async.h:431
SC::Result start(AsyncEventLoop &eventLoop, FileDescriptor::Handle process)
Sets async request members and calls AsyncEventLoop::start.
Function< void(Result &)> callback
Called when process has exited.
Definition Async.h:456
Base class for all async requests, holding state and type.
Definition Async.h:139
bool isCancelling() const
Returns true if this request is being cancelled.
AsyncRequest(Type type)
Constructs a free async request of given type.
Definition Async.h:181
Result start(AsyncEventLoop &eventLoop)
Shortcut for AsyncEventLoop::start.
uint16_t getUserFlags() const
Gets user flags, holding some meaningful data for the caller.
Definition Async.h:211
Function< void(AsyncResult &)> * getCloseCallback()
Returns currently set close callback (if any) passed to AsyncRequest::stop.
Definition Async.h:214
bool isActive() const
Returns true if this request is active or being reactivated.
Result executeOn(AsyncTaskSequence &task, ThreadPool &pool, AsyncThreadPoolMode mode=AsyncThreadPoolMode::NativePreferred)
Adds the request to be executed on a specific AsyncTaskSequence.
bool isFree() const
Returns true if this request is free.
void disableThreadPool()
Disables the thread-pool usage for this request.
Type getType() const
Returns request type.
Definition Async.h:202
void setUserFlags(uint16_t externalFlags)
Sets user flags, holding some meaningful data for the caller.
Definition Async.h:208
Result stop(AsyncEventLoop &eventLoop, Function< void(AsyncResult &)> *afterStopped=nullptr)
Ask to stop current async operation.
void executeOn(AsyncSequence &sequence)
Adds the request to be executed on a specific AsyncSequence.
Type
Type of async request.
Definition Async.h:159
Helper holding CompletionData for a specific AsyncRequest-derived class.
Definition Async.h:318
Base class for all async results (argument of completion callbacks).
Definition Async.h:288
const SC::Result & isValid() const
Check if the returnCode of this result is valid.
Definition Async.h:299
AsyncResult(AsyncEventLoop &eventLoop, AsyncRequest &request, SC::Result &res, bool *hasBeenReactivated=nullptr)
Constructs an async result from a request and a result.
Definition Async.h:290
void reactivateRequest(bool shouldBeReactivated)
Ask the event loop to re-activate this request after it was already completed.
Execute AsyncRequests serially, by submitting the next one after the previous one is completed.
Definition Async.h:264
Options for AsyncSignal request configuration.
Definition Async.h:474
Mode
Reserved signal watching policy.
Definition Async.h:480
@ Persistent
Default policy; future backend parity work may use it for automatic persistence.
@ OneShot
Future policy for explicit one-shot watchers.
Mode mode
Currently does not bypass the AsyncRequest reactivation contract.
Definition Async.h:484
bool coalesce
Backend hint; portable code should inspect CompletionData::deliveryCount.
Definition Async.h:485
Definition Async.h:512
Definition Async.h:518
Starts monitoring a signal, notifying about its reception.
Definition Async.h:508
Function< void(Result &)> callback
Called when the signal is raised.
Definition Async.h:526
SC::Result start(AsyncEventLoop &eventLoop, int num, AsyncSignalOptions options={})
Sets async request members and calls AsyncEventLoop::start.
Starts a socket accept operation, obtaining a new socket from a listening socket.
Definition Async.h:605
SC::Result start(AsyncEventLoop &eventLoop, const SocketDescriptor &socketDescriptor)
Sets async request members and calls AsyncEventLoop::start.
Starts a socket connect operation, connecting to a remote endpoint.
Definition Async.h:625
Function< void(Result &)> callback
Called after socket is finally connected to endpoint.
Definition Async.h:636
SC::Result start(AsyncEventLoop &eventLoop, const SocketDescriptor &descriptor, SocketIPAddress address)
Sets async request members and calls AsyncEventLoop::start.
Starts an unconnected socket receive from operation, receiving bytes from a remote endpoint.
Definition Async.h:809
Definition Async.h:755
SC::Result get(Span< char > &outData)
Get a Span of the actually read data.
Definition Async.h:765
SocketIPAddress getSourceAddress() const
Returns the source when it is an IPv4 or IPv6 address.
SocketAddress getSourceSocketAddress() const
Returns the family-neutral source address for receive-from operations.
Starts a socket receive operation, receiving bytes from a remote endpoint.
Definition Async.h:744
SC::Result start(AsyncEventLoop &eventLoop, const SocketDescriptor &descriptor, Span< char > data)
Sets async request members and calls AsyncEventLoop::start.
SC::Result closeHandle()
The Socket Descriptor handle to read data from.
Definition Async.h:788
Span< char > buffer
The writeable span of memory where to data will be written.
Definition Async.h:785
Function< void(Result &)> callback
Called after data has been received.
Definition Async.h:783
Starts an unconnected socket send to operation, sending bytes to a remote endpoint.
Definition Async.h:706
Starts a socket send operation, sending bytes to a remote endpoint.
Definition Async.h:660
Function< void(Result &)> callback
Called when socket is ready to send more data.
Definition Async.h:675
SC::Result start(AsyncEventLoop &eventLoop, const SocketDescriptor &descriptor, Span< const char > data)
Sets async request members and calls AsyncEventLoop::start.
Span< Span< const char > > buffers
Spans of bytes to send (singleBuffer == false)
Definition Async.h:682
Span< const char > buffer
Span of bytes to send (singleBuffer == true)
Definition Async.h:681
SC::Result start(AsyncEventLoop &eventLoop, const SocketDescriptor &descriptor, Span< Span< const char > > data)
Sets async request members and calls AsyncEventLoop::start.
An AsyncSequence using a SC::ThreadPool to execute one or more SC::AsyncRequest in a background threa...
Definition Async.h:1242
Atomic variables (only for int and bool for now).
Definition Atomic.h:42
An automatically reset event object to synchronize two threads.
Definition Threading.h:243
[UniqueHandleDeclaration2Snippet]
Definition File.h:130
Options used to open a file descriptor.
Definition File.h:101
A structure to describe copy flags.
Definition FileSystem.h:77
Read / Write pipe (Process stdin/stdout and IPC communication)
Definition File.h:302
Family-neutral native socket address.
Definition Socket.h:168
Low-level OS socket handle.
Definition Socket.h:207
SocketType
Sets the socket type to datagram or stream.
Definition Socket.h:82
AddressFamily
Sets the socket address family.
Definition Socket.h:74
ProtocolType
Sets the socket protocol type.
Definition Socket.h:89
Native representation of an IP Address.
Definition Socket.h:117
A small task containing a function to execute that can be queued in the thread pool.
Definition ThreadPool.h:16
Simple thread pool that executes tasks in a fixed number of worker threads.
Definition ThreadPool.h:45
A native OS thread.
Definition Threading.h:127