| // Copyright 2012 The Rust Project Developers. See the COPYRIGHT |
| // file at the top-level directory of this distribution and at |
| // http://rust-lang.org/COPYRIGHT. |
| // |
| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| // option. This file may not be copied, modified, or distributed |
| // except according to those terms. |
| |
| |
| /** |
| A single runtime instance. |
| |
| The kernel is primarily responsible for managing the lifetime of |
| schedulers, which in turn run rust tasks. It provides a memory |
| allocator and logging service for use by other runtime components, |
| it creates unique task ids. |
| |
| The kernel runs until there are no live schedulers. |
| |
| The kernel internally runs an additional, special scheduler called |
| the 'osmain' (or platform) scheduler, which schedules tasks on the |
| thread that is running the kernel (normally the thread on which the |
| C main function was called). This scheduler may be used by Rust |
| code for interacting with platform APIs that insist on being called |
| from the main thread. |
| |
| The requirements of the osmain scheduler has resulted in a complex |
| process for creating and running scheduler loops that involves |
| a thing called a 'rust_sched_launcher_factory' whose function I've |
| already forgotten. rust_scheduler is the main scheduler class, |
| and tasks are scheduled on individual threads by rust_sched_loop. |
| |
| Ideally all the in-memory Rust state is encapsulated by a kernel |
| instance, but there is still some truly global data in the runtime |
| (like the check claims flag). |
| */ |
| |
| #ifndef RUST_KERNEL_H |
| #define RUST_KERNEL_H |
| |
| #include "rust_globals.h" |
| |
| #include <map> |
| #include <vector> |
| |
| #include "rust_exchange_alloc.h" |
| #include "rust_log.h" |
| #include "rust_sched_reaper.h" |
| #include "rust_type.h" |
| #include "sync/lock_and_signal.h" |
| |
| class rust_scheduler; |
| class rust_sched_driver; |
| class rust_sched_launcher_factory; |
| struct rust_task_thread; |
| |
| // Scheduler, task handles. These uniquely identify within a |
| // single kernel instance the objects they represent. |
| typedef intptr_t rust_sched_id; |
| typedef intptr_t rust_task_id; |
| |
| typedef std::map<rust_sched_id, rust_scheduler*> sched_map; |
| |
| // This is defined as a struct only because we need a single pointer to pass |
| // to the Rust function that runs the at_exit functions |
| struct exit_functions { |
| size_t count; |
| fn_env_pair **start; |
| }; |
| |
| class rust_kernel { |
| rust_exchange_alloc exchange_alloc; |
| rust_log _log; |
| |
| // The next task id |
| rust_task_id max_task_id; |
| |
| lock_and_signal rval_lock; |
| int rval; |
| |
| // Protects max_sched_id and sched_table, join_list, killed, |
| // already_exiting |
| lock_and_signal sched_lock; |
| // The next scheduler id |
| rust_sched_id max_sched_id; |
| // A map from scheduler ids to schedulers. When this is empty |
| // the kernel terminates |
| sched_map sched_table; |
| // A list of scheduler ids that are ready to exit |
| std::vector<rust_sched_id> join_list; |
| // Whether or not the runtime has to die (triggered when the root/main |
| // task group fails). This propagates to all new schedulers and tasks |
| // created after it is set. |
| bool killed; |
| bool already_exiting; |
| |
| |
| rust_sched_reaper sched_reaper; |
| |
| // The primary scheduler |
| rust_sched_id main_scheduler; |
| // The single-threaded scheduler that uses the main thread |
| rust_sched_id osmain_scheduler; |
| // Runs the single-threaded scheduler that executes tasks |
| // on the main thread |
| rust_sched_driver *osmain_driver; |
| |
| // An atomically updated count of the live, 'non-weak' tasks |
| uintptr_t non_weak_tasks; |
| |
| rust_scheduler* get_scheduler_by_id_nolock(rust_sched_id id); |
| void allow_scheduler_exit(); |
| void begin_shutdown(); |
| |
| lock_and_signal at_exit_lock; |
| spawn_fn at_exit_runner; |
| bool at_exit_started; |
| std::vector<fn_env_pair*> at_exit_fns; |
| exit_functions final_exit_fns; |
| |
| void run_exit_functions(); |
| |
| public: |
| struct rust_env *env; |
| uintptr_t global_data; |
| |
| rust_kernel(rust_env *env); |
| |
| void log(uint32_t level, char const *fmt, ...); |
| void fatal(char const *fmt, ...); |
| |
| void *malloc(size_t size, const char *tag); |
| void *realloc(void *mem, size_t size); |
| void free(void *mem); |
| rust_exchange_alloc *region() { return &exchange_alloc; } |
| |
| void fail(); |
| |
| rust_sched_id create_scheduler(size_t num_threads); |
| rust_sched_id create_scheduler(rust_sched_launcher_factory *launchfac, |
| size_t num_threads, bool allow_exit); |
| rust_scheduler* get_scheduler_by_id(rust_sched_id id); |
| // Called by a scheduler to indicate that it is terminating |
| void release_scheduler_id(rust_sched_id id); |
| void wait_for_schedulers(); |
| int run(); |
| |
| #ifdef __WIN32__ |
| void win32_require(LPCTSTR fn, BOOL ok); |
| #endif |
| |
| rust_task_id generate_task_id(); |
| |
| void set_exit_status(int code); |
| |
| rust_sched_id main_sched_id() { return main_scheduler; } |
| rust_sched_id osmain_sched_id() { return osmain_scheduler; } |
| |
| void inc_live_count(); |
| void dec_live_count(); |
| |
| void register_exit_function(spawn_fn runner, fn_env_pair *f); |
| }; |
| |
| template <typename T> struct kernel_owned { |
| inline void *operator new(size_t size, rust_kernel *kernel, |
| const char *tag) { |
| return kernel->malloc(size, tag); |
| } |
| |
| void operator delete(void *ptr) { |
| ((T *)ptr)->kernel->free(ptr); |
| } |
| }; |
| |
| #endif /* RUST_KERNEL_H */ |
| |
| // |
| // Local Variables: |
| // mode: C++ |
| // fill-column: 78; |
| // indent-tabs-mode: nil |
| // c-basic-offset: 4 |
| // buffer-file-coding-system: utf-8-unix |
| // End: |
| // |