| 1 | #pragma once
|
|---|
| 2 |
|
|---|
| 3 | #include "Thread.h"
|
|---|
| 4 | #include "Memory.h"
|
|---|
| 5 |
|
|---|
| 6 | namespace mil {
|
|---|
| 7 |
|
|---|
| 8 | class Tls {
|
|---|
| 9 | struct Data {
|
|---|
| 10 | #ifdef MIL_GUI_WINDOWS
|
|---|
| 11 | HWND window_cache;
|
|---|
| 12 | #else
|
|---|
| 13 | NSWindow* window_cache;
|
|---|
| 14 | #endif
|
|---|
| 15 | } data[MIL_MAX_THREADS];
|
|---|
| 16 | Data dummy;
|
|---|
| 17 | public:
|
|---|
| 18 | Data& getData(thread::id_t thread_id) {
|
|---|
| 19 | if (!thread::is_valid_id(thread_id)) {
|
|---|
| 20 | // Error
|
|---|
| 21 | return dummy;
|
|---|
| 22 | }
|
|---|
| 23 | return data[thread_id];
|
|---|
| 24 | }
|
|---|
| 25 | void flush() {
|
|---|
| 26 | for (size_t i = 0; i < _countof(data); i++) {
|
|---|
| 27 | data[i].window_cache = NULL;
|
|---|
| 28 | }
|
|---|
| 29 | }
|
|---|
| 30 | const thread::id_t thread_id;
|
|---|
| 31 | pool::Producer producer;
|
|---|
| 32 | pool::Consumer consumer;
|
|---|
| 33 | Tls(thread::id_t thread_id) : thread_id(thread_id), producer(thread_id) {
|
|---|
| 34 | memset(&data, 0, sizeof(data));
|
|---|
| 35 | memset(&dummy, 0, sizeof(dummy));
|
|---|
| 36 | }
|
|---|
| 37 | };
|
|---|
| 38 |
|
|---|
| 39 | struct ExitEvent {
|
|---|
| 40 | typedef SFINAE_CONDITION IsExitEvent;
|
|---|
| 41 | };
|
|---|
| 42 |
|
|---|
| 43 | struct ModuleExecuteProxy {
|
|---|
| 44 | template <class EventData, class Target>
|
|---|
| 45 | static void execute_body(EventData& data, Target& target, typename EventData::IsReturnMemoryEvent) {
|
|---|
| 46 | target.tls.producer.free(data.memory);
|
|---|
| 47 | }
|
|---|
| 48 |
|
|---|
| 49 | template <class EventData, class Target>
|
|---|
| 50 | static void execute_body(EventData&, Target& target, typename EventData::IsExitEvent) {
|
|---|
| 51 | MIL_MODULE_SUPER_CHILD_TYPE(Target)& o =
|
|---|
| 52 | MIL_MODULE_GET_SUPER_CHILD(target);
|
|---|
| 53 | o.destroy();
|
|---|
| 54 | }
|
|---|
| 55 |
|
|---|
| 56 | template <class EventData, class Target>
|
|---|
| 57 | static void execute_body(EventData& data, Target& target, ...) {
|
|---|
| 58 | MIL_MODULE_SUPER_CHILD_TYPE(Target)& o =
|
|---|
| 59 | MIL_MODULE_GET_SUPER_CHILD(target);
|
|---|
| 60 |
|
|---|
| 61 | o.execute_hook(data);
|
|---|
| 62 | o.execute(data);
|
|---|
| 63 | }
|
|---|
| 64 |
|
|---|
| 65 | // template <class, class Target>
|
|---|
| 66 | // static void execute_body(ExitEvent, Target& target, ...) {
|
|---|
| 67 | // MIL_MODULE_SUPER_CHILD_TYPE(Target)& o =
|
|---|
| 68 | // MIL_MODULE_GET_SUPER_CHILD(target);
|
|---|
| 69 | // o.destroy();
|
|---|
| 70 | // }
|
|---|
| 71 |
|
|---|
| 72 | template <class EventData, class Target>
|
|---|
| 73 | static void execute(EventData& data, Target& target) {
|
|---|
| 74 | execute_body<EventData, Target>(data, target, SFINAE_DUMMY_VALUE);
|
|---|
| 75 | }
|
|---|
| 76 | };
|
|---|
| 77 |
|
|---|
| 78 | template <class T>
|
|---|
| 79 | void post_exit_template(void* obj, void* event_memory) {
|
|---|
| 80 | MIL_MODULE_SUPER_CHILD_TYPE(T)& o =
|
|---|
| 81 | MIL_MODULE_GET_SUPER_CHILD(*reinterpret_cast<T*>(obj));
|
|---|
| 82 |
|
|---|
| 83 | o.requestExit(event_memory);
|
|---|
| 84 | }
|
|---|
| 85 |
|
|---|
| 86 | template <class T>
|
|---|
| 87 | void join_template(void* obj) {
|
|---|
| 88 | MIL_MODULE_SUPER_CHILD_TYPE(T)& o =
|
|---|
| 89 | MIL_MODULE_GET_SUPER_CHILD(*reinterpret_cast<T*>(obj));
|
|---|
| 90 |
|
|---|
| 91 | o.join();
|
|---|
| 92 | }
|
|---|
| 93 |
|
|---|
| 94 | struct AutoJoiner {
|
|---|
| 95 | void* obj;
|
|---|
| 96 | void (*post_exit)(void*, void*);
|
|---|
| 97 | void (*join)(void*);
|
|---|
| 98 | char event_memory[sizeof(void*) * 10];
|
|---|
| 99 | };
|
|---|
| 100 |
|
|---|
| 101 | void set_auto_join_body(AutoJoiner&);
|
|---|
| 102 | void do_auto_join();
|
|---|
| 103 |
|
|---|
| 104 | void set_tmalloc_post_body(void (*post)());
|
|---|
| 105 |
|
|---|
| 106 | template <class T>
|
|---|
| 107 | void set_auto_join(T* t) {
|
|---|
| 108 | AutoJoiner a = {};
|
|---|
| 109 | a.obj = reinterpret_cast<void*>(t);
|
|---|
| 110 | a.post_exit = post_exit_template<T>;
|
|---|
| 111 | a.join = join_template<T>;
|
|---|
| 112 | set_auto_join_body(a);
|
|---|
| 113 | }
|
|---|
| 114 |
|
|---|
| 115 | template <class Event, class Target, class Sender>
|
|---|
| 116 | void dispatcher_free_event(Event& event, Target& target) {
|
|---|
| 117 | if (is_exit_event<Event>()) {
|
|---|
| 118 | return;
|
|---|
| 119 | }
|
|---|
| 120 |
|
|---|
| 121 | if (is_return_memory_event<Event>() || unlikely(event.owner_id == target.thread_id)) {
|
|---|
| 122 | // ReturnMemoryEvent
|
|---|
| 123 | size_t blocks = pool::bytes_to_blocks(return_memory_considered_sizeof<Event>());
|
|---|
| 124 | target.tls.producer.free(&event, blocks);
|
|---|
| 125 | return;
|
|---|
| 126 | }
|
|---|
| 127 |
|
|---|
| 128 | pool::MemoryList* m = target.tls.consumer.pop(event.owner_id);
|
|---|
| 129 | if (!m) {
|
|---|
| 130 | target.tls.consumer.store(&event);
|
|---|
| 131 | return;
|
|---|
| 132 | }
|
|---|
| 133 |
|
|---|
| 134 | pool::ReturnMemoryEvent<sizeof(Event)> e;
|
|---|
| 135 | e.memory = m;
|
|---|
| 136 | void* sender = thread::get(event.owner_id);
|
|---|
| 137 | if (unlikely(!sender)) {
|
|---|
| 138 | return;
|
|---|
| 139 | }
|
|---|
| 140 | (reinterpret_cast<Sender*>(sender))->post(e, target, (void*)&event, event.owner_id);
|
|---|
| 141 | }
|
|---|
| 142 |
|
|---|
| 143 | typedef void (*post_tfree_memory_function)(void*, pool::MemoryList*, thread::id_t);
|
|---|
| 144 | extern post_tfree_memory_function posts[MIL_MAX_THREADS];
|
|---|
| 145 |
|
|---|
| 146 | template <class Child, template <class> class ThreadType = MIL_DEFAULT_THREAD>
|
|---|
| 147 | class ModuleCommon : public Thread<ModuleCommon<Child, ThreadType>, ThreadType> {
|
|---|
| 148 | public:
|
|---|
| 149 | Tls tls;
|
|---|
| 150 | MIL_CRTP_CLASS_MEMBERS;
|
|---|
| 151 |
|
|---|
| 152 | template <class Event>
|
|---|
| 153 | void execute_hook_(Event&) {}
|
|---|
| 154 |
|
|---|
| 155 | template <class Event>
|
|---|
| 156 | void execute_hook(Event&) // no bracket
|
|---|
| 157 |
|
|---|
| 158 |
|
|---|
| 159 | ModuleCommon() : tls(this->thread_id) {
|
|---|
| 160 | set_auto_join(&MIL_MODULE_GET_SUPER_CHILD(*this));
|
|---|
| 161 | posts[this->thread_id] = &post_tfree_memory<Child>;
|
|---|
| 162 | }
|
|---|
| 163 |
|
|---|
| 164 | ~ModuleCommon() {
|
|---|
| 165 | }
|
|---|
| 166 |
|
|---|
| 167 | protected:
|
|---|
| 168 | struct TMemory {
|
|---|
| 169 | void setMalloced() {
|
|---|
| 170 | owner_id |= (1 << (sizeof(owner_id) * 8 - 1));
|
|---|
| 171 | }
|
|---|
| 172 | bool isMalloced() {
|
|---|
| 173 | return (owner_id & (1 << (sizeof(owner_id) * 8 - 1))) ? true : false;
|
|---|
| 174 | }
|
|---|
| 175 | mil::thread::id_t owner_id;
|
|---|
| 176 | };
|
|---|
| 177 | struct TMemoryStore {
|
|---|
| 178 | union {
|
|---|
| 179 | mil::thread::id_t owner_id;
|
|---|
| 180 | char padding[pool::BLOCK_SIZE];
|
|---|
| 181 | };
|
|---|
| 182 | };
|
|---|
| 183 |
|
|---|
| 184 | template <class Receiver>
|
|---|
| 185 | static void post_tfree_memory(void* memory, pool::MemoryList* list, thread::id_t receiver_id) {
|
|---|
| 186 | pool::ReturnMemoryEvent<pool::BLOCK_SIZE> e;
|
|---|
| 187 | e.memory = list;
|
|---|
| 188 | Receiver& receiver = *(reinterpret_cast<Receiver*>(thread::get(receiver_id)));
|
|---|
| 189 | receiver.post(e, receiver, memory, receiver_id);
|
|---|
| 190 | }
|
|---|
| 191 |
|
|---|
| 192 | void* tmalloc(size_t size) {
|
|---|
| 193 | TMemory* tmemory = NULL;
|
|---|
| 194 | if ((size + sizeof(TMemory)) <= mil::pool::BLOCK_SIZE) {
|
|---|
| 195 | tmemory = (TMemory*)tls.producer.malloc<mil::pool::BLOCK_SIZE>();
|
|---|
| 196 | tmemory->owner_id = this->thread_id;
|
|---|
| 197 | } else {
|
|---|
| 198 | tmemory = (TMemory*)malloc(size + sizeof(TMemory));
|
|---|
| 199 | tmemory->setMalloced();
|
|---|
| 200 | }
|
|---|
| 201 | return (void*)(((TMemory*)tmemory) + 1);
|
|---|
| 202 | }
|
|---|
| 203 |
|
|---|
| 204 | void tfree(void* memory_) {
|
|---|
| 205 | TMemory* tmemory = (((TMemory*)memory_) - 1);
|
|---|
| 206 | if (tmemory->isMalloced()) {
|
|---|
| 207 | free(tmemory);
|
|---|
| 208 | return;
|
|---|
| 209 | }
|
|---|
| 210 |
|
|---|
| 211 | pool::MemoryList* m = this->tls.consumer.pop(tmemory->owner_id);
|
|---|
| 212 | if (!m) {
|
|---|
| 213 | this->tls.consumer.store((TMemoryStore*)tmemory);
|
|---|
| 214 | return;
|
|---|
| 215 | }
|
|---|
| 216 |
|
|---|
| 217 | posts[tmemory->owner_id](tmemory, m, tmemory->owner_id);
|
|---|
| 218 | }
|
|---|
| 219 | };
|
|---|
| 220 |
|
|---|
| 221 | class ExitNotifier : public ModuleCommon<ExitNotifier, MIL_DEFAULT_THREAD> {
|
|---|
| 222 | public:
|
|---|
| 223 | void requestExit(void*) {
|
|---|
| 224 | }
|
|---|
| 225 |
|
|---|
| 226 | template <typename T, typename Sender>
|
|---|
| 227 | void post(const T&, Sender&, void*, thread::id_t) {
|
|---|
| 228 | }
|
|---|
| 229 |
|
|---|
| 230 | template <typename T, typename Sender>
|
|---|
| 231 | void post(const T& event, Sender& sender) {
|
|---|
| 232 | }
|
|---|
| 233 | };
|
|---|
| 234 | extern ExitNotifier exitNotifier;
|
|---|
| 235 |
|
|---|
| 236 | }
|
|---|
| 237 |
|
|---|