opengris-scaler 1.12.7__cp312-cp312-manylinux_2_28_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of opengris-scaler might be problematic. Click here for more details.
- opengris_scaler-1.12.7.dist-info/METADATA +729 -0
- opengris_scaler-1.12.7.dist-info/RECORD +232 -0
- opengris_scaler-1.12.7.dist-info/WHEEL +5 -0
- opengris_scaler-1.12.7.dist-info/entry_points.txt +9 -0
- opengris_scaler-1.12.7.dist-info/licenses/LICENSE +201 -0
- opengris_scaler-1.12.7.dist-info/licenses/LICENSE.spdx +7 -0
- opengris_scaler-1.12.7.dist-info/licenses/NOTICE +8 -0
- opengris_scaler.libs/libcapnp-1-b787335c.1.0.so +0 -0
- opengris_scaler.libs/libkj-1-094aa318.1.0.so +0 -0
- scaler/CMakeLists.txt +11 -0
- scaler/__init__.py +14 -0
- scaler/about.py +5 -0
- scaler/client/__init__.py +0 -0
- scaler/client/agent/__init__.py +0 -0
- scaler/client/agent/client_agent.py +210 -0
- scaler/client/agent/disconnect_manager.py +27 -0
- scaler/client/agent/future_manager.py +112 -0
- scaler/client/agent/heartbeat_manager.py +74 -0
- scaler/client/agent/mixins.py +89 -0
- scaler/client/agent/object_manager.py +98 -0
- scaler/client/agent/task_manager.py +64 -0
- scaler/client/client.py +635 -0
- scaler/client/future.py +252 -0
- scaler/client/object_buffer.py +129 -0
- scaler/client/object_reference.py +25 -0
- scaler/client/serializer/__init__.py +0 -0
- scaler/client/serializer/default.py +16 -0
- scaler/client/serializer/mixins.py +38 -0
- scaler/cluster/__init__.py +0 -0
- scaler/cluster/cluster.py +115 -0
- scaler/cluster/combo.py +148 -0
- scaler/cluster/object_storage_server.py +45 -0
- scaler/cluster/scheduler.py +83 -0
- scaler/config/__init__.py +0 -0
- scaler/config/defaults.py +87 -0
- scaler/config/loader.py +95 -0
- scaler/config/mixins.py +15 -0
- scaler/config/section/__init__.py +0 -0
- scaler/config/section/cluster.py +56 -0
- scaler/config/section/native_worker_adapter.py +44 -0
- scaler/config/section/object_storage_server.py +7 -0
- scaler/config/section/scheduler.py +53 -0
- scaler/config/section/symphony_worker_adapter.py +47 -0
- scaler/config/section/top.py +13 -0
- scaler/config/section/webui.py +16 -0
- scaler/config/types/__init__.py +0 -0
- scaler/config/types/object_storage_server.py +45 -0
- scaler/config/types/worker.py +57 -0
- scaler/config/types/zmq.py +79 -0
- scaler/entry_points/__init__.py +0 -0
- scaler/entry_points/cluster.py +133 -0
- scaler/entry_points/object_storage_server.py +41 -0
- scaler/entry_points/scheduler.py +135 -0
- scaler/entry_points/top.py +286 -0
- scaler/entry_points/webui.py +26 -0
- scaler/entry_points/worker_adapter_native.py +137 -0
- scaler/entry_points/worker_adapter_symphony.py +102 -0
- scaler/io/__init__.py +0 -0
- scaler/io/async_binder.py +85 -0
- scaler/io/async_connector.py +95 -0
- scaler/io/async_object_storage_connector.py +185 -0
- scaler/io/mixins.py +154 -0
- scaler/io/sync_connector.py +68 -0
- scaler/io/sync_object_storage_connector.py +185 -0
- scaler/io/sync_subscriber.py +83 -0
- scaler/io/utility.py +31 -0
- scaler/io/ymq/CMakeLists.txt +98 -0
- scaler/io/ymq/__init__.py +0 -0
- scaler/io/ymq/_ymq.pyi +96 -0
- scaler/io/ymq/_ymq.so +0 -0
- scaler/io/ymq/bytes.h +114 -0
- scaler/io/ymq/common.h +29 -0
- scaler/io/ymq/configuration.h +60 -0
- scaler/io/ymq/epoll_context.cpp +185 -0
- scaler/io/ymq/epoll_context.h +85 -0
- scaler/io/ymq/error.h +132 -0
- scaler/io/ymq/event_loop.h +55 -0
- scaler/io/ymq/event_loop_thread.cpp +64 -0
- scaler/io/ymq/event_loop_thread.h +46 -0
- scaler/io/ymq/event_manager.h +81 -0
- scaler/io/ymq/file_descriptor.h +203 -0
- scaler/io/ymq/interruptive_concurrent_queue.h +169 -0
- scaler/io/ymq/io_context.cpp +98 -0
- scaler/io/ymq/io_context.h +44 -0
- scaler/io/ymq/io_socket.cpp +299 -0
- scaler/io/ymq/io_socket.h +121 -0
- scaler/io/ymq/iocp_context.cpp +102 -0
- scaler/io/ymq/iocp_context.h +83 -0
- scaler/io/ymq/logging.h +163 -0
- scaler/io/ymq/message.h +15 -0
- scaler/io/ymq/message_connection.h +16 -0
- scaler/io/ymq/message_connection_tcp.cpp +672 -0
- scaler/io/ymq/message_connection_tcp.h +96 -0
- scaler/io/ymq/network_utils.h +179 -0
- scaler/io/ymq/pymod_ymq/bytes.h +113 -0
- scaler/io/ymq/pymod_ymq/exception.h +124 -0
- scaler/io/ymq/pymod_ymq/gil.h +15 -0
- scaler/io/ymq/pymod_ymq/io_context.h +166 -0
- scaler/io/ymq/pymod_ymq/io_socket.h +285 -0
- scaler/io/ymq/pymod_ymq/message.h +99 -0
- scaler/io/ymq/pymod_ymq/python.h +153 -0
- scaler/io/ymq/pymod_ymq/ymq.cpp +23 -0
- scaler/io/ymq/pymod_ymq/ymq.h +357 -0
- scaler/io/ymq/readme.md +114 -0
- scaler/io/ymq/simple_interface.cpp +80 -0
- scaler/io/ymq/simple_interface.h +24 -0
- scaler/io/ymq/tcp_client.cpp +367 -0
- scaler/io/ymq/tcp_client.h +75 -0
- scaler/io/ymq/tcp_operations.h +41 -0
- scaler/io/ymq/tcp_server.cpp +410 -0
- scaler/io/ymq/tcp_server.h +79 -0
- scaler/io/ymq/third_party/concurrentqueue.h +3747 -0
- scaler/io/ymq/timed_queue.h +272 -0
- scaler/io/ymq/timestamp.h +102 -0
- scaler/io/ymq/typedefs.h +20 -0
- scaler/io/ymq/utils.h +34 -0
- scaler/io/ymq/ymq.py +130 -0
- scaler/object_storage/CMakeLists.txt +50 -0
- scaler/object_storage/__init__.py +0 -0
- scaler/object_storage/constants.h +11 -0
- scaler/object_storage/defs.h +14 -0
- scaler/object_storage/io_helper.cpp +44 -0
- scaler/object_storage/io_helper.h +9 -0
- scaler/object_storage/message.cpp +56 -0
- scaler/object_storage/message.h +130 -0
- scaler/object_storage/object_manager.cpp +126 -0
- scaler/object_storage/object_manager.h +52 -0
- scaler/object_storage/object_storage_server.cpp +359 -0
- scaler/object_storage/object_storage_server.h +126 -0
- scaler/object_storage/object_storage_server.so +0 -0
- scaler/object_storage/pymod_object_storage_server.cpp +104 -0
- scaler/protocol/__init__.py +0 -0
- scaler/protocol/capnp/__init__.py +0 -0
- scaler/protocol/capnp/_python.py +6 -0
- scaler/protocol/capnp/common.capnp +63 -0
- scaler/protocol/capnp/message.capnp +216 -0
- scaler/protocol/capnp/object_storage.capnp +52 -0
- scaler/protocol/capnp/status.capnp +73 -0
- scaler/protocol/introduction.md +105 -0
- scaler/protocol/python/__init__.py +0 -0
- scaler/protocol/python/common.py +135 -0
- scaler/protocol/python/message.py +726 -0
- scaler/protocol/python/mixins.py +13 -0
- scaler/protocol/python/object_storage.py +118 -0
- scaler/protocol/python/status.py +279 -0
- scaler/protocol/worker.md +228 -0
- scaler/scheduler/__init__.py +0 -0
- scaler/scheduler/allocate_policy/__init__.py +0 -0
- scaler/scheduler/allocate_policy/allocate_policy.py +9 -0
- scaler/scheduler/allocate_policy/capability_allocate_policy.py +280 -0
- scaler/scheduler/allocate_policy/even_load_allocate_policy.py +159 -0
- scaler/scheduler/allocate_policy/mixins.py +55 -0
- scaler/scheduler/controllers/__init__.py +0 -0
- scaler/scheduler/controllers/balance_controller.py +65 -0
- scaler/scheduler/controllers/client_controller.py +131 -0
- scaler/scheduler/controllers/config_controller.py +31 -0
- scaler/scheduler/controllers/graph_controller.py +424 -0
- scaler/scheduler/controllers/information_controller.py +81 -0
- scaler/scheduler/controllers/mixins.py +201 -0
- scaler/scheduler/controllers/object_controller.py +147 -0
- scaler/scheduler/controllers/scaling_controller.py +86 -0
- scaler/scheduler/controllers/task_controller.py +373 -0
- scaler/scheduler/controllers/worker_controller.py +168 -0
- scaler/scheduler/object_usage/__init__.py +0 -0
- scaler/scheduler/object_usage/object_tracker.py +131 -0
- scaler/scheduler/scheduler.py +253 -0
- scaler/scheduler/task/__init__.py +0 -0
- scaler/scheduler/task/task_state_machine.py +92 -0
- scaler/scheduler/task/task_state_manager.py +61 -0
- scaler/ui/__init__.py +0 -0
- scaler/ui/constants.py +9 -0
- scaler/ui/live_display.py +118 -0
- scaler/ui/memory_window.py +146 -0
- scaler/ui/setting_page.py +47 -0
- scaler/ui/task_graph.py +370 -0
- scaler/ui/task_log.py +83 -0
- scaler/ui/utility.py +35 -0
- scaler/ui/webui.py +125 -0
- scaler/ui/worker_processors.py +85 -0
- scaler/utility/__init__.py +0 -0
- scaler/utility/debug.py +19 -0
- scaler/utility/event_list.py +63 -0
- scaler/utility/event_loop.py +58 -0
- scaler/utility/exceptions.py +42 -0
- scaler/utility/formatter.py +44 -0
- scaler/utility/graph/__init__.py +0 -0
- scaler/utility/graph/optimization.py +27 -0
- scaler/utility/graph/topological_sorter.py +11 -0
- scaler/utility/graph/topological_sorter_graphblas.py +174 -0
- scaler/utility/identifiers.py +105 -0
- scaler/utility/logging/__init__.py +0 -0
- scaler/utility/logging/decorators.py +25 -0
- scaler/utility/logging/scoped_logger.py +33 -0
- scaler/utility/logging/utility.py +183 -0
- scaler/utility/many_to_many_dict.py +123 -0
- scaler/utility/metadata/__init__.py +0 -0
- scaler/utility/metadata/profile_result.py +31 -0
- scaler/utility/metadata/task_flags.py +30 -0
- scaler/utility/mixins.py +13 -0
- scaler/utility/network_util.py +7 -0
- scaler/utility/one_to_many_dict.py +72 -0
- scaler/utility/queues/__init__.py +0 -0
- scaler/utility/queues/async_indexed_queue.py +37 -0
- scaler/utility/queues/async_priority_queue.py +70 -0
- scaler/utility/queues/async_sorted_priority_queue.py +45 -0
- scaler/utility/queues/indexed_queue.py +114 -0
- scaler/utility/serialization.py +9 -0
- scaler/version.txt +1 -0
- scaler/worker/__init__.py +0 -0
- scaler/worker/agent/__init__.py +0 -0
- scaler/worker/agent/heartbeat_manager.py +107 -0
- scaler/worker/agent/mixins.py +137 -0
- scaler/worker/agent/processor/__init__.py +0 -0
- scaler/worker/agent/processor/object_cache.py +107 -0
- scaler/worker/agent/processor/processor.py +279 -0
- scaler/worker/agent/processor/streaming_buffer.py +28 -0
- scaler/worker/agent/processor_holder.py +145 -0
- scaler/worker/agent/processor_manager.py +365 -0
- scaler/worker/agent/profiling_manager.py +109 -0
- scaler/worker/agent/task_manager.py +150 -0
- scaler/worker/agent/timeout_manager.py +19 -0
- scaler/worker/preload.py +84 -0
- scaler/worker/worker.py +264 -0
- scaler/worker_adapter/__init__.py +0 -0
- scaler/worker_adapter/native.py +154 -0
- scaler/worker_adapter/symphony/__init__.py +0 -0
- scaler/worker_adapter/symphony/callback.py +45 -0
- scaler/worker_adapter/symphony/heartbeat_manager.py +79 -0
- scaler/worker_adapter/symphony/message.py +24 -0
- scaler/worker_adapter/symphony/task_manager.py +288 -0
- scaler/worker_adapter/symphony/worker.py +205 -0
- scaler/worker_adapter/symphony/worker_adapter.py +142 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <deque>
|
|
4
|
+
#include <memory>
|
|
5
|
+
#include <optional>
|
|
6
|
+
#include <queue>
|
|
7
|
+
|
|
8
|
+
#include "scaler/io/ymq/configuration.h"
|
|
9
|
+
#include "scaler/io/ymq/io_socket.h"
|
|
10
|
+
#include "scaler/io/ymq/message_connection.h"
|
|
11
|
+
#include "scaler/io/ymq/tcp_operations.h"
|
|
12
|
+
|
|
13
|
+
namespace scaler {
|
|
14
|
+
namespace ymq {
|
|
15
|
+
|
|
16
|
+
class EventLoopThread;
|
|
17
|
+
class EventManager;
|
|
18
|
+
|
|
19
|
+
class MessageConnectionTCP: public MessageConnection {
|
|
20
|
+
public:
|
|
21
|
+
using SendMessageCallback = Configuration::SendMessageCallback;
|
|
22
|
+
using RecvMessageCallback = Configuration::RecvMessageCallback;
|
|
23
|
+
|
|
24
|
+
MessageConnectionTCP(
|
|
25
|
+
std::shared_ptr<EventLoopThread> eventLoopThread,
|
|
26
|
+
int connFd,
|
|
27
|
+
sockaddr localAddr,
|
|
28
|
+
sockaddr remoteAddr,
|
|
29
|
+
std::string localIOSocketIdentity,
|
|
30
|
+
bool responsibleForRetry,
|
|
31
|
+
std::shared_ptr<std::queue<RecvMessageCallback>> _pendingRecvMessageCallbacks) noexcept;
|
|
32
|
+
|
|
33
|
+
MessageConnectionTCP(
|
|
34
|
+
std::shared_ptr<EventLoopThread> eventLoopThread,
|
|
35
|
+
std::string localIOSocketIdentity,
|
|
36
|
+
std::string remoteIOSocketIdentity,
|
|
37
|
+
std::shared_ptr<std::queue<RecvMessageCallback>> _pendingRecvMessageCallbacks) noexcept;
|
|
38
|
+
|
|
39
|
+
~MessageConnectionTCP() noexcept;
|
|
40
|
+
|
|
41
|
+
void onCreated();
|
|
42
|
+
|
|
43
|
+
void sendMessage(Message msg, SendMessageCallback onMessageSent);
|
|
44
|
+
bool recvMessage();
|
|
45
|
+
void disconnect();
|
|
46
|
+
|
|
47
|
+
std::shared_ptr<EventLoopThread> _eventLoopThread;
|
|
48
|
+
const sockaddr _remoteAddr;
|
|
49
|
+
const bool _responsibleForRetry;
|
|
50
|
+
std::optional<std::string> _remoteIOSocketIdentity;
|
|
51
|
+
|
|
52
|
+
private:
|
|
53
|
+
enum class IOError {
|
|
54
|
+
Drained,
|
|
55
|
+
Aborted,
|
|
56
|
+
Disconnected,
|
|
57
|
+
MessageTooLarge,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
void onRead();
|
|
61
|
+
void onWrite();
|
|
62
|
+
void onClose();
|
|
63
|
+
void onError()
|
|
64
|
+
{
|
|
65
|
+
onRead();
|
|
66
|
+
// onClose();
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
std::expected<void, IOError> tryReadOneMessage();
|
|
70
|
+
std::expected<void, IOError> tryReadMessages();
|
|
71
|
+
std::expected<size_t, IOError> trySendQueuedMessages();
|
|
72
|
+
void updateWriteOperations(size_t n);
|
|
73
|
+
void updateReadOperation();
|
|
74
|
+
|
|
75
|
+
void setRemoteIdentity() noexcept;
|
|
76
|
+
|
|
77
|
+
std::unique_ptr<EventManager> _eventManager;
|
|
78
|
+
int _connFd;
|
|
79
|
+
sockaddr _localAddr;
|
|
80
|
+
std::string _localIOSocketIdentity;
|
|
81
|
+
|
|
82
|
+
std::deque<TcpWriteOperation> _writeOperations;
|
|
83
|
+
size_t _sendCursor;
|
|
84
|
+
|
|
85
|
+
std::shared_ptr<std::queue<RecvMessageCallback>> _pendingRecvMessageCallbacks;
|
|
86
|
+
std::queue<TcpReadOperation> _receivedReadOperations;
|
|
87
|
+
|
|
88
|
+
bool _disconnect;
|
|
89
|
+
|
|
90
|
+
constexpr static bool isCompleteMessage(const TcpReadOperation& x);
|
|
91
|
+
friend void IOSocket::onConnectionIdentityReceived(MessageConnectionTCP* conn) noexcept;
|
|
92
|
+
friend void IOSocket::onConnectionDisconnected(MessageConnectionTCP* conn, bool keepInBook) noexcept;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
} // namespace ymq
|
|
96
|
+
} // namespace scaler
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#ifdef __linux__
|
|
4
|
+
#include <arpa/inet.h>
|
|
5
|
+
#include <netinet/in.h>
|
|
6
|
+
#include <netinet/tcp.h>
|
|
7
|
+
#include <unistd.h>
|
|
8
|
+
#endif // __linux__
|
|
9
|
+
#ifdef _WIN32
|
|
10
|
+
// clang-format off
|
|
11
|
+
#include <windows.h>
|
|
12
|
+
#include <winsock2.h>
|
|
13
|
+
#include <ws2tcpip.h>
|
|
14
|
+
// clang-format on
|
|
15
|
+
#endif // _WIN32
|
|
16
|
+
|
|
17
|
+
#include <string.h>
|
|
18
|
+
|
|
19
|
+
#include <cassert>
|
|
20
|
+
#include <expected>
|
|
21
|
+
|
|
22
|
+
#include "scaler/io/ymq/error.h"
|
|
23
|
+
|
|
24
|
+
namespace scaler {
|
|
25
|
+
namespace ymq {
|
|
26
|
+
|
|
27
|
+
inline auto GetErrorCode()
|
|
28
|
+
{
|
|
29
|
+
#ifdef __linux__
|
|
30
|
+
return errno;
|
|
31
|
+
#endif // __linux__
|
|
32
|
+
#ifdef _WIN32
|
|
33
|
+
return WSAGetLastError();
|
|
34
|
+
#endif // _WIN32
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
inline constexpr void CloseAndZeroSocket(auto& fd)
|
|
38
|
+
{
|
|
39
|
+
#ifdef __linux__
|
|
40
|
+
close(fd);
|
|
41
|
+
#endif // __linux__
|
|
42
|
+
#ifdef _WIN32
|
|
43
|
+
closesocket(fd);
|
|
44
|
+
#endif // _WIN32
|
|
45
|
+
fd = 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
inline std::expected<sockaddr, int> stringToSockaddr(const std::string& address)
|
|
49
|
+
{
|
|
50
|
+
// Check and strip the "tcp://" prefix
|
|
51
|
+
static const std::string prefix = "tcp://";
|
|
52
|
+
if (address.substr(0, prefix.size()) != prefix) {
|
|
53
|
+
unrecoverableError({
|
|
54
|
+
Error::ErrorCode::InvalidAddressFormat,
|
|
55
|
+
"Originated from",
|
|
56
|
+
__PRETTY_FUNCTION__,
|
|
57
|
+
"Your input is",
|
|
58
|
+
address,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
std::string addr_part = address.substr(prefix.size());
|
|
63
|
+
size_t colon_pos = addr_part.find(':');
|
|
64
|
+
if (colon_pos == std::string::npos) {
|
|
65
|
+
unrecoverableError({
|
|
66
|
+
Error::ErrorCode::InvalidAddressFormat,
|
|
67
|
+
"Originated from",
|
|
68
|
+
__PRETTY_FUNCTION__,
|
|
69
|
+
"Your input is",
|
|
70
|
+
address,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
std::string ip = addr_part.substr(0, colon_pos);
|
|
75
|
+
std::string port_str = addr_part.substr(colon_pos + 1);
|
|
76
|
+
|
|
77
|
+
int port = 0;
|
|
78
|
+
try {
|
|
79
|
+
port = std::stoi(port_str);
|
|
80
|
+
} catch (...) {
|
|
81
|
+
unrecoverableError({
|
|
82
|
+
Error::ErrorCode::InvalidAddressFormat,
|
|
83
|
+
"Originated from",
|
|
84
|
+
__PRETTY_FUNCTION__,
|
|
85
|
+
"Your input is",
|
|
86
|
+
address,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
sockaddr_in out_addr {};
|
|
91
|
+
out_addr.sin_family = AF_INET;
|
|
92
|
+
out_addr.sin_port = htons(port);
|
|
93
|
+
|
|
94
|
+
int res = inet_pton(AF_INET, ip.c_str(), &out_addr.sin_addr);
|
|
95
|
+
if (res == 0) {
|
|
96
|
+
unrecoverableError({
|
|
97
|
+
Error::ErrorCode::InvalidAddressFormat,
|
|
98
|
+
"Originated from",
|
|
99
|
+
__PRETTY_FUNCTION__,
|
|
100
|
+
"Your input is",
|
|
101
|
+
address,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (res == -1) {
|
|
106
|
+
unrecoverableError({
|
|
107
|
+
Error::ErrorCode::ConfigurationError,
|
|
108
|
+
"Originated from",
|
|
109
|
+
__PRETTY_FUNCTION__,
|
|
110
|
+
"Errno is",
|
|
111
|
+
strerror(errno),
|
|
112
|
+
"out_addr.sin_family",
|
|
113
|
+
out_addr.sin_family,
|
|
114
|
+
"out_addr.sin_port",
|
|
115
|
+
out_addr.sin_port,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return *(sockaddr*)&out_addr;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
inline int setNoDelay(int fd)
|
|
123
|
+
{
|
|
124
|
+
int optval = 1;
|
|
125
|
+
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&optval, sizeof(optval)) == -1) {
|
|
126
|
+
unrecoverableError({
|
|
127
|
+
Error::ErrorCode::ConfigurationError,
|
|
128
|
+
"Originated from",
|
|
129
|
+
__PRETTY_FUNCTION__,
|
|
130
|
+
"Errno is",
|
|
131
|
+
strerror(errno),
|
|
132
|
+
"fd",
|
|
133
|
+
fd,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return fd;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
inline sockaddr getLocalAddr(int fd)
|
|
141
|
+
{
|
|
142
|
+
sockaddr localAddr = {};
|
|
143
|
+
socklen_t localAddrLen = sizeof(localAddr);
|
|
144
|
+
if (getsockname(fd, &localAddr, &localAddrLen) == -1) {
|
|
145
|
+
unrecoverableError({
|
|
146
|
+
Error::ErrorCode::ConfigurationError,
|
|
147
|
+
"Originated from",
|
|
148
|
+
__PRETTY_FUNCTION__,
|
|
149
|
+
"Errno is",
|
|
150
|
+
strerror(errno),
|
|
151
|
+
"fd",
|
|
152
|
+
fd,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
return localAddr;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
inline sockaddr getRemoteAddr(int fd)
|
|
159
|
+
{
|
|
160
|
+
sockaddr remoteAddr = {};
|
|
161
|
+
socklen_t remoteAddrLen = sizeof(remoteAddr);
|
|
162
|
+
|
|
163
|
+
if (getpeername(fd, &remoteAddr, &remoteAddrLen) == -1) {
|
|
164
|
+
unrecoverableError({
|
|
165
|
+
Error::ErrorCode::ConfigurationError,
|
|
166
|
+
"Originated from",
|
|
167
|
+
__PRETTY_FUNCTION__,
|
|
168
|
+
"Errno is",
|
|
169
|
+
strerror(errno),
|
|
170
|
+
"fd",
|
|
171
|
+
fd,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return remoteAddr;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
} // namespace ymq
|
|
179
|
+
} // namespace scaler
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
// Python
|
|
4
|
+
#include "scaler/io/ymq/pymod_ymq/python.h"
|
|
5
|
+
|
|
6
|
+
// First-party
|
|
7
|
+
#include "scaler/io/ymq/bytes.h"
|
|
8
|
+
|
|
9
|
+
struct PyBytesYMQ {
|
|
10
|
+
PyObject_HEAD;
|
|
11
|
+
Bytes bytes;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
extern "C" {
|
|
15
|
+
|
|
16
|
+
static int PyBytesYMQ_init(PyBytesYMQ* self, PyObject* args, PyObject* kwds)
|
|
17
|
+
{
|
|
18
|
+
Py_buffer view {.buf = nullptr};
|
|
19
|
+
const char* keywords[] = {"bytes", nullptr};
|
|
20
|
+
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|y*", (char**)keywords, &view))
|
|
21
|
+
return -1; // Error parsing arguments
|
|
22
|
+
|
|
23
|
+
if (!view.buf) {
|
|
24
|
+
// If no bytes were provided, initialize with an empty Bytes object
|
|
25
|
+
self->bytes = Bytes();
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// copy the data into the Bytes object
|
|
30
|
+
// it might be possible to make this zero-copy in the future
|
|
31
|
+
self->bytes = Bytes((char*)view.buf, view.len);
|
|
32
|
+
|
|
33
|
+
PyBuffer_Release(&view);
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static void PyBytesYMQ_dealloc(PyBytesYMQ* self)
|
|
38
|
+
{
|
|
39
|
+
try {
|
|
40
|
+
self->bytes.~Bytes(); // Call the destructor to free the Bytes object
|
|
41
|
+
} catch (...) {
|
|
42
|
+
PyErr_SetString(PyExc_RuntimeError, "Failed to deallocate Bytes");
|
|
43
|
+
PyErr_WriteUnraisable((PyObject*)self);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
auto* tp = Py_TYPE(self);
|
|
47
|
+
tp->tp_free(self);
|
|
48
|
+
Py_DECREF(tp);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static PyObject* PyBytesYMQ_repr(PyBytesYMQ* self)
|
|
52
|
+
{
|
|
53
|
+
if (self->bytes.is_null()) {
|
|
54
|
+
return PyUnicode_FromString("<Bytes: empty>");
|
|
55
|
+
} else {
|
|
56
|
+
return PyUnicode_FromFormat("<Bytes: %db>", self->bytes.len());
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static PyObject* PyBytesYMQ_data_getter(PyBytesYMQ* self)
|
|
61
|
+
{
|
|
62
|
+
if (self->bytes.is_null())
|
|
63
|
+
Py_RETURN_NONE;
|
|
64
|
+
|
|
65
|
+
return PyBytes_FromStringAndSize((const char*)self->bytes.data(), self->bytes.len());
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static Py_ssize_t PyBytesYMQ_len(PyBytesYMQ* self)
|
|
69
|
+
{
|
|
70
|
+
return self->bytes.len();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static PyObject* PyBytesYMQ_len_getter(PyBytesYMQ* self)
|
|
74
|
+
{
|
|
75
|
+
return PyLong_FromSize_t(self->bytes.len());
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static int PyBytesYMQ_getbuffer(PyBytesYMQ* self, Py_buffer* view, int flags)
|
|
79
|
+
{
|
|
80
|
+
return PyBuffer_FillInfo(view, (PyObject*)self, (void*)self->bytes.data(), self->bytes.len(), true, flags);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
static void PyBytesYMQ_releasebuffer(PyBytesYMQ* self, Py_buffer* view)
|
|
84
|
+
{
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static PyGetSetDef PyBytesYMQ_properties[] = {
|
|
89
|
+
{"data", (getter)PyBytesYMQ_data_getter, nullptr, PyDoc_STR("Data of the Bytes object"), nullptr},
|
|
90
|
+
{"len", (getter)PyBytesYMQ_len_getter, nullptr, PyDoc_STR("Length of the Bytes object"), nullptr},
|
|
91
|
+
{nullptr, nullptr, nullptr, nullptr, nullptr}, // Sentinel
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
static PyType_Slot PyBytesYMQ_slots[] = {
|
|
95
|
+
{Py_tp_init, (void*)PyBytesYMQ_init},
|
|
96
|
+
{Py_tp_dealloc, (void*)PyBytesYMQ_dealloc},
|
|
97
|
+
{Py_tp_repr, (void*)PyBytesYMQ_repr},
|
|
98
|
+
{Py_mp_length, (void*)PyBytesYMQ_len},
|
|
99
|
+
{Py_tp_getset, (void*)PyBytesYMQ_properties},
|
|
100
|
+
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION > 8
|
|
101
|
+
{Py_bf_getbuffer, (void*)PyBytesYMQ_getbuffer},
|
|
102
|
+
{Py_bf_releasebuffer, (void*)PyBytesYMQ_releasebuffer},
|
|
103
|
+
#endif
|
|
104
|
+
{0, nullptr},
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
static PyType_Spec PyBytesYMQ_spec = {
|
|
108
|
+
.name = "_ymq.Bytes",
|
|
109
|
+
.basicsize = sizeof(PyBytesYMQ),
|
|
110
|
+
.itemsize = 0,
|
|
111
|
+
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE,
|
|
112
|
+
.slots = PyBytesYMQ_slots,
|
|
113
|
+
};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
// Python
|
|
4
|
+
#include "scaler/io/ymq/pymod_ymq/python.h"
|
|
5
|
+
|
|
6
|
+
// First-party
|
|
7
|
+
#include "scaler/io/ymq/error.h"
|
|
8
|
+
#include "scaler/io/ymq/pymod_ymq/ymq.h"
|
|
9
|
+
|
|
10
|
+
using namespace scaler::ymq;
|
|
11
|
+
|
|
12
|
+
// the order of the members in the exception args tuple
|
|
13
|
+
const Py_ssize_t YMQException_errorCodeIndex = 0;
|
|
14
|
+
const Py_ssize_t YMQException_messageIndex = 1;
|
|
15
|
+
|
|
16
|
+
struct YMQException {
|
|
17
|
+
PyException_HEAD;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
extern "C" {
|
|
21
|
+
|
|
22
|
+
static int YMQException_init(YMQException* self, PyObject* args, PyObject* kwds)
|
|
23
|
+
{
|
|
24
|
+
auto state = YMQStateFromSelf((PyObject*)self);
|
|
25
|
+
if (!state)
|
|
26
|
+
return -1;
|
|
27
|
+
|
|
28
|
+
// no need to incref these because we don't store them
|
|
29
|
+
// Furthermore, this fn does not create a strong reference to the args
|
|
30
|
+
PyObject* errorCode = nullptr;
|
|
31
|
+
PyObject* errorMessage = nullptr;
|
|
32
|
+
if (!PyArg_ParseTuple(args, "OO", &errorCode, &errorMessage))
|
|
33
|
+
return -1;
|
|
34
|
+
|
|
35
|
+
if (!PyObject_IsInstance(errorCode, *state->PyErrorCodeType)) {
|
|
36
|
+
PyErr_SetString(PyExc_TypeError, "expected code to be of type ErrorCode");
|
|
37
|
+
return -1;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!PyUnicode_Check(errorMessage)) {
|
|
41
|
+
PyErr_SetString(PyExc_TypeError, "expected message to be a string");
|
|
42
|
+
return -1;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// delegate to the base class init
|
|
46
|
+
return self->ob_base.ob_type->tp_base->tp_init((PyObject*)self, args, kwds);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static void YMQException_dealloc(YMQException* self)
|
|
50
|
+
{
|
|
51
|
+
self->ob_base.ob_type->tp_base->tp_dealloc((PyObject*)self);
|
|
52
|
+
|
|
53
|
+
// we still need to release the reference to the heap type
|
|
54
|
+
auto* tp = Py_TYPE(self);
|
|
55
|
+
Py_DECREF(tp);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static PyObject* YMQException_code_getter(YMQException* self, void* Py_UNUSED(closure))
|
|
59
|
+
{
|
|
60
|
+
return PySequence_GetItem(self->args, YMQException_errorCodeIndex);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
static PyObject* YMQException_message_getter(YMQException* self, void* Py_UNUSED(closure))
|
|
64
|
+
{
|
|
65
|
+
return PySequence_GetItem(self->args, YMQException_messageIndex);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static PyGetSetDef YMQException_getset[] = {
|
|
70
|
+
{"code", (getter)YMQException_code_getter, nullptr, PyDoc_STR("error code"), nullptr},
|
|
71
|
+
{"message", (getter)YMQException_message_getter, nullptr, PyDoc_STR("error message"), nullptr},
|
|
72
|
+
{nullptr} // Sentinel
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
static PyType_Slot YMQException_slots[] = {
|
|
76
|
+
{Py_tp_init, (void*)YMQException_init},
|
|
77
|
+
{Py_tp_dealloc, (void*)YMQException_dealloc},
|
|
78
|
+
{Py_tp_getset, (void*)YMQException_getset},
|
|
79
|
+
{0, 0},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
static PyType_Spec YMQException_spec = {
|
|
83
|
+
"_ymq.YMQException", sizeof(YMQException), 0, Py_TPFLAGS_DEFAULT, YMQException_slots};
|
|
84
|
+
|
|
85
|
+
inline OwnedPyObject<> YMQException_argtupleFromCoreError(YMQState* state, const Error* error)
|
|
86
|
+
{
|
|
87
|
+
OwnedPyObject code = PyLong_FromLong(static_cast<long>(error->_errorCode));
|
|
88
|
+
|
|
89
|
+
if (!code)
|
|
90
|
+
return nullptr;
|
|
91
|
+
|
|
92
|
+
OwnedPyObject pyCode = PyObject_CallFunction(*state->PyErrorCodeType, "O", *code);
|
|
93
|
+
|
|
94
|
+
if (!pyCode)
|
|
95
|
+
return nullptr;
|
|
96
|
+
|
|
97
|
+
OwnedPyObject message = PyUnicode_FromString(error->what());
|
|
98
|
+
|
|
99
|
+
if (!message)
|
|
100
|
+
return nullptr;
|
|
101
|
+
|
|
102
|
+
return PyTuple_Pack(2, *pyCode, *message);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
inline void YMQException_setFromCoreError(YMQState* state, const Error* error)
|
|
106
|
+
{
|
|
107
|
+
auto tuple = YMQException_argtupleFromCoreError(state, error);
|
|
108
|
+
if (!tuple)
|
|
109
|
+
return;
|
|
110
|
+
|
|
111
|
+
PyErr_SetObject(*state->PyExceptionType, *tuple);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
inline PyObject* YMQException_createFromCoreError(YMQState* state, const Error* error)
|
|
115
|
+
{
|
|
116
|
+
auto tuple = YMQException_argtupleFromCoreError(state, error);
|
|
117
|
+
if (!tuple)
|
|
118
|
+
return nullptr;
|
|
119
|
+
|
|
120
|
+
OwnedPyObject exc = PyObject_CallObject(*state->PyExceptionType, *tuple);
|
|
121
|
+
|
|
122
|
+
// transfer ownership to caller
|
|
123
|
+
return exc.take();
|
|
124
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#include "scaler/io/ymq/pymod_ymq/python.h"
|
|
2
|
+
|
|
3
|
+
class AcquireGIL {
|
|
4
|
+
public:
|
|
5
|
+
AcquireGIL() : _state(PyGILState_Ensure()) {}
|
|
6
|
+
~AcquireGIL() { PyGILState_Release(_state); }
|
|
7
|
+
|
|
8
|
+
AcquireGIL(const AcquireGIL&) = delete;
|
|
9
|
+
AcquireGIL& operator=(const AcquireGIL&) = delete;
|
|
10
|
+
AcquireGIL(AcquireGIL&&) = delete;
|
|
11
|
+
AcquireGIL& operator=(AcquireGIL&&) = delete;
|
|
12
|
+
|
|
13
|
+
private:
|
|
14
|
+
PyGILState_STATE _state;
|
|
15
|
+
};
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
// Python
|
|
4
|
+
#include "scaler/io/ymq/pymod_ymq/python.h"
|
|
5
|
+
|
|
6
|
+
// C++
|
|
7
|
+
#include <memory>
|
|
8
|
+
|
|
9
|
+
// First-party
|
|
10
|
+
#include "scaler/io/ymq/configuration.h"
|
|
11
|
+
#include "scaler/io/ymq/io_context.h"
|
|
12
|
+
#include "scaler/io/ymq/io_socket.h"
|
|
13
|
+
#include "scaler/io/ymq/pymod_ymq/io_socket.h"
|
|
14
|
+
#include "scaler/io/ymq/pymod_ymq/ymq.h"
|
|
15
|
+
|
|
16
|
+
// TODO: move ymq's python module into this namespace
|
|
17
|
+
using namespace scaler::ymq;
|
|
18
|
+
using Identity = Configuration::IOSocketIdentity;
|
|
19
|
+
|
|
20
|
+
struct PyIOContext {
|
|
21
|
+
PyObject_HEAD;
|
|
22
|
+
std::shared_ptr<IOContext> ioContext;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
extern "C" {
|
|
26
|
+
|
|
27
|
+
static int PyIOContext_init(PyIOContext* self, PyObject* args, PyObject* kwds)
|
|
28
|
+
{
|
|
29
|
+
// default to 1 thread if not specified
|
|
30
|
+
Py_ssize_t numThreads = 1;
|
|
31
|
+
const char* kwlist[] = {"num_threads", nullptr};
|
|
32
|
+
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|n", (char**)kwlist, &numThreads))
|
|
33
|
+
return -1;
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
new (&self->ioContext) std::shared_ptr<IOContext>();
|
|
37
|
+
self->ioContext = std::make_shared<IOContext>(numThreads);
|
|
38
|
+
} catch (...) {
|
|
39
|
+
PyErr_SetString(PyExc_RuntimeError, "Failed to create IOContext");
|
|
40
|
+
return -1;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static void PyIOContext_dealloc(PyIOContext* self)
|
|
47
|
+
{
|
|
48
|
+
try {
|
|
49
|
+
self->ioContext.~shared_ptr();
|
|
50
|
+
} catch (...) {
|
|
51
|
+
PyErr_SetString(PyExc_RuntimeError, "Failed to deallocate IOContext");
|
|
52
|
+
PyErr_WriteUnraisable((PyObject*)self);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
auto* tp = Py_TYPE(self);
|
|
56
|
+
tp->tp_free(self);
|
|
57
|
+
Py_DECREF(tp);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static PyObject* PyIOContext_repr(PyIOContext* self)
|
|
61
|
+
{
|
|
62
|
+
return PyUnicode_FromFormat("<IOContext at %p>", (void*)self->ioContext.get());
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static PyObject* PyIOContext_numThreads_getter(PyIOContext* self, void* Py_UNUSED(closure))
|
|
66
|
+
{
|
|
67
|
+
return PyLong_FromSize_t(self->ioContext->numThreads());
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
static PyObject* PyIOContext_createIOSocket(PyIOContext* self, PyObject* args, PyObject* kwargs)
|
|
71
|
+
{
|
|
72
|
+
YMQState* state = YMQStateFromSelf((PyObject*)self);
|
|
73
|
+
if (!state)
|
|
74
|
+
return nullptr;
|
|
75
|
+
|
|
76
|
+
PyObject* callback = nullptr;
|
|
77
|
+
const char* identity = nullptr;
|
|
78
|
+
Py_ssize_t identityLen = 0;
|
|
79
|
+
PyObject* pySocketType = nullptr;
|
|
80
|
+
const char* kwlist[] = {"", "identity", "socket_type", nullptr};
|
|
81
|
+
if (!PyArg_ParseTupleAndKeywords(
|
|
82
|
+
args, kwargs, "Os#O", (char**)kwlist, &callback, &identity, &identityLen, &pySocketType))
|
|
83
|
+
return nullptr;
|
|
84
|
+
|
|
85
|
+
if (!PyObject_IsInstance(pySocketType, *state->PyIOSocketEnumType)) {
|
|
86
|
+
PyErr_SetString(PyExc_TypeError, "Expected socket_type to be an instance of IOSocketType");
|
|
87
|
+
return nullptr;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
OwnedPyObject value = PyObject_GetAttrString(pySocketType, "value");
|
|
91
|
+
if (!value)
|
|
92
|
+
return nullptr;
|
|
93
|
+
|
|
94
|
+
if (!PyLong_Check(*value)) {
|
|
95
|
+
PyErr_SetString(PyExc_TypeError, "Expected socket_type to be an integer");
|
|
96
|
+
return nullptr;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
long socketTypeValue = PyLong_AsLong(*value);
|
|
100
|
+
if (socketTypeValue < 0 && PyErr_Occurred())
|
|
101
|
+
return nullptr;
|
|
102
|
+
|
|
103
|
+
IOSocketType socketType = static_cast<IOSocketType>(socketTypeValue);
|
|
104
|
+
OwnedPyObject<PyIOSocket> ioSocket = PyObject_New(PyIOSocket, (PyTypeObject*)*state->PyIOSocketType);
|
|
105
|
+
if (!ioSocket)
|
|
106
|
+
return nullptr;
|
|
107
|
+
|
|
108
|
+
Py_INCREF(callback);
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
// ensure the fields are init
|
|
112
|
+
new (&ioSocket->socket) std::shared_ptr<IOSocket>();
|
|
113
|
+
new (&ioSocket->ioContext) std::shared_ptr<IOContext>();
|
|
114
|
+
ioSocket->ioContext = self->ioContext;
|
|
115
|
+
|
|
116
|
+
self->ioContext->createIOSocket(
|
|
117
|
+
std::string(identity, identityLen), socketType, [callback, ioSocket](auto socket) {
|
|
118
|
+
AcquireGIL _;
|
|
119
|
+
|
|
120
|
+
ioSocket->socket = socket;
|
|
121
|
+
OwnedPyObject _result = PyObject_CallFunctionObjArgs(callback, *ioSocket, nullptr);
|
|
122
|
+
Py_DECREF(callback);
|
|
123
|
+
});
|
|
124
|
+
} catch (...) {
|
|
125
|
+
PyErr_SetString(PyExc_RuntimeError, "Failed to create IOSocket");
|
|
126
|
+
return nullptr;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
Py_RETURN_NONE;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
} // extern "C"
|
|
133
|
+
|
|
134
|
+
static PyMethodDef PyIOContext_methods[] = {
|
|
135
|
+
{"createIOSocket",
|
|
136
|
+
(PyCFunction)PyIOContext_createIOSocket,
|
|
137
|
+
METH_VARARGS | METH_KEYWORDS,
|
|
138
|
+
PyDoc_STR("Create a new IOSocket")},
|
|
139
|
+
{nullptr, nullptr, 0, nullptr},
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
static PyGetSetDef PyIOContext_properties[] = {
|
|
143
|
+
{"num_threads",
|
|
144
|
+
(getter)PyIOContext_numThreads_getter,
|
|
145
|
+
nullptr,
|
|
146
|
+
PyDoc_STR("Get the number of threads in the IOContext"),
|
|
147
|
+
nullptr},
|
|
148
|
+
{nullptr, nullptr, nullptr, nullptr, nullptr},
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
static PyType_Slot PyIOContext_slots[] = {
|
|
152
|
+
{Py_tp_init, (void*)PyIOContext_init},
|
|
153
|
+
{Py_tp_dealloc, (void*)PyIOContext_dealloc},
|
|
154
|
+
{Py_tp_repr, (void*)PyIOContext_repr},
|
|
155
|
+
{Py_tp_methods, (void*)PyIOContext_methods},
|
|
156
|
+
{Py_tp_getset, (void*)PyIOContext_properties},
|
|
157
|
+
{0, nullptr},
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
static PyType_Spec PyIOContext_spec = {
|
|
161
|
+
.name = "_ymq.BaseIOContext",
|
|
162
|
+
.basicsize = sizeof(PyIOContext),
|
|
163
|
+
.itemsize = 0,
|
|
164
|
+
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_BASETYPE,
|
|
165
|
+
.slots = PyIOContext_slots,
|
|
166
|
+
};
|