# os.h ## Overview
Abstraction layer for common fundamental OS services, such as file systems, threads, memory, sockets, etc. To add engine support for a new OS you should implement these services. To work cross-platform, many of the data structures in this file just store an opaque data blob, big enough to fit then native OS type on all platforms we support. Then we just `memcpy()` data back and forth between the native type and this data blob.
## Index
Virtual memory

`struct tm_os_virtual_memory_api`
`map()`
`unmap()`
`reserve()`
`commit()`

File I/O
`struct tm_file_o`
`struct tm_file_time_o`

`struct tm_os_file_io_api`
`open_input()`
`open_output()`
`open_append()`
`set_position()`
`size()`
`read()`
`write()`
`read_at()`
`write_at()`
`set_last_modified_time()`
`close()`

File System
`struct tm_file_stat_t`
`struct tm_strings_t`
`struct tm_file_system_watcher_o`
`tm_file_system_detailed_watcher_o`
`enum tm_file_system_change_action`
`struct tm_file_system_change_t`

`struct tm_os_file_system_api`
`stat()`
`directory_entries()`
`make_directory()`
`remove_file()`
`remove_directory()`
`rename()`
`copy_file()`
`getcwd()`
`chdir()`
`is_absolute()`
`absolute()`
`temp_directory()`
`create_watcher()`
`any_changes()`
`destroy_watcher()`
`create_detailed_watcher()`
`detailed_changes()`
`destroy_detailed_watcher()`
`app_folder()`

DLL
`struct tm_dll_o`

`struct tm_os_dll_api`
`open()`
`get()`
`sym()`
`close()`

Socket
`struct tm_socket_o`
`struct tm_socket_address_t`
`TM_SOCKET_IP_LOCALHOST`
`TM_SOCKET_IP_BROADCAST`
`enum tm_os_socket_type`
`enum tm_os_socket_error`
`enum tm_os_socket_connect`
`enum tm_os_socket_getaddrinfo`
`enum tm_os_socket_option`

`struct tm_os_socket_api`
`init()`
`shutdown()`
`socket()`
`set_option()`
`bind()`
`getsockname()`
`listen()`
`accept()`
`connect()`
`send()`
`recv()`
`sendto()`
`recvfrom()`
`close()`
`getaddrinfo()`
`getaddrinfo_async()`
`getaddrinfo_result()`

Threading
`enum tm_os_thread__priority`
`tm_thread_entry_f`
`tm_fiber_entry_f`
`struct tm_critical_section_o`
`struct tm_semaphore_o`
`struct tm_thread_o`
`struct tm_fiber_o`

`struct tm_os_thread_api`

Critical sections
`create_critical_section()`
`enter_critical_section()`
`leave_critical_section()`
`destroy_critical_section()`

Semaphores
`create_semaphore()`
`semaphore_add()`
`semaphore_wait()`
`semaphore_poll()`
`destroy_semaphore()`

Threads
`thread_id()`
`processor_id()`
`create_thread()`
`set_thread_priority()`
`wait_for_thread()`
`thread_id_from_tm_thread()`

Fibers
`convert_thread_to_fiber()`
`convert_fiber_to_thread()`
`create_fiber()`
`destroy_fiber()`
`switch_to_fiber()`
`fiber_user_data()`

Misc
`yield_processor()`
`sleep()`

`TM_OS_ENTER_CRITICAL_SECTION()`
`TM_OS_LEAVE_CRITICAL_SECTION()`

Time

`struct tm_os_time_api`
`now()`
`delta()`
`add()`
`file_time_now()`
`file_time_delta()`

OS Dialogs
`struct tm_os_dialogs_open_t`
`struct tm_os_dialogs_open_res_t`
`struct tm_os_dialogs_save_t`

`struct tm_os_dialogs_api`
`open()`
`open_folder()`
`save()`
`message_box()`
`show_count()`

Info

`struct tm_os_info_api`
`num_logical_processors()`
`avx_support()`

Debugger

`struct tm_os_debugger_api`
`is_debugger_present()`
`debug_break()`

System

`struct tm_os_system_api`
`open_url()`
`open_file()`
`exe_path()`
`execute()`
`execute_in_background()`
`execute_stdout()`

Master API
`TM_OS_API_NAME`

`struct tm_os_api`
`virtual_memory`
`file_io`
`file_system`
`dll`
`socket`
`thread`
`time`
`dialogs`
`info`
`debugger`
`system`

## API

Virtual memory

### `struct tm_os_virtual_memory_api`
Interface to the virtual memory system. !!! WARNING Calling these functions directly will bypass our memory tracking system. Instead of calling these functions directly, you should use the allocators defined in the `tm_allocator_api`. #### `map()` ~~~c void *(*map)(uint64_t size); ~~~ Maps an area of the specified size and returns a pointer to it. #### `unmap()` ~~~c void (*unmap)(void *p, uint64_t size); ~~~ Unmaps an area mapped with `map()`. #### `reserve()` ~~~c void *(*reserve)(uint64_t size); ~~~ Reserves an address range without commiting the reserved addresses to actual memory. `reserve()` and `commit()` together are equal to `map()`. Note that a reserved address range can be committed in parts. `unmap()` will free reserved addresses whether they have been committed or not. #### `commit()` ~~~c void (*commit)(void *p, uint64_t size); ~~~ Commits reserved memory.

File I/O

### `struct tm_file_o`
Represents a file handle. ~~~c typedef struct tm_file_o { // Opaque OS representation of file handle. uint64_t handle; // True if `tm_file_o` represents a valid file handle. bool valid; TM_PAD(7); } tm_file_o; ~~~
### `struct tm_file_time_o`
Represents a time in the file system (such as the time a file was last modified). You can assume the time to be monotonically increasing, i.e. a larger `opaque` value represents a later time, but you shouldn't assume anything else about what the `opaque` value represents or the resolution of the timer. Instead, use `tm_os_time_api->file_time_delta()` to convert elapsed time to seconds. ~~~c typedef struct tm_file_time_o { uint64_t opaque; } tm_file_time_o; ~~~
### `struct tm_os_file_io_api`
Interface for File I/O. #### `open_input()` ~~~c tm_file_o (*open_input)(const char *path); ~~~ Opens the specified path for input. If opening fails, returns an invalid file handle. #### `open_output()` ~~~c tm_file_o (*open_output)(const char *path); ~~~ Opens the specified path for output. If the file doesn't exist, it will be created. If the file exists, it will be truncated. Use `open_append()` to open a file for writing without truncating it. If opening fails, returns an invalid file handle. #### `open_append()` ~~~c tm_file_o (*open_append)(const char *path); ~~~ As `open_output()`, but opens the file for appending. I.e., the existing file content will not be truncated. #### `set_position()` ~~~c void (*set_position)(tm_file_o file, uint64_t pos); ~~~ Sets the read/write offset from the start of the file. #### `size()` ~~~c uint64_t (*size)(tm_file_o file); ~~~ Returns the current size of the file. #### `read()` ~~~c int64_t (*read)(tm_file_o file, void *buffer, uint64_t size); ~~~ Reads `size` bytes into the `buffer` from the current file position. If the file size is smaller than the requested read, the function will read the number of bytes that are available and return the number of read bytes. At EOF, the function will return 0. If there is an error, -1 is returned. #### `write()` ~~~c bool (*write)(tm_file_o file, const void *buffer, uint64_t size); ~~~ Writes `size` bytes from `buffer` to the file. Returns `true` on success and `false` otherwise. #### `read_at()` ~~~c int64_t (*read_at)(tm_file_o file, uint64_t offset, void *buffer, uint64_t size); ~~~ As `read()`, but reads from a specific offset in the file. This allows multiple threads to read and write to the file without being disturbed by changes to the file offset made by other threads. #### `write_at()` ~~~c bool (*write_at)(tm_file_o file, uint64_t offset, const void *buffer, uint64_t size); ~~~ As `write()`, but writes to a specific offset in the file. This allows multiple threads to read and write to the file without being disturbed by changes to the file offset made by other threads. #### `set_last_modified_time()` ~~~c void (*set_last_modified_time)(tm_file_o file, struct tm_file_time_o time); ~~~ Sets the last modified time of `file`. #### `close()` ~~~c void (*close)(tm_file_o file); ~~~ Closes the file.

File System

### `struct tm_file_stat_t`
Information about a file returned by the `stat()` function. ~~~c typedef struct tm_file_stat_t { // True if the file (or directory) exists. bool exists; // True if the file is a directory. bool is_directory; TM_PAD(6); // The time the file was last modified. struct tm_file_time_o last_modified_time; // The size of the file. uint64_t size; } tm_file_stat_t; ~~~
### `struct tm_strings_t`
Represents a collection of strings. The struct is followed by `char[bytes - sizeof(struct tm_strings_t)]` bytes of string data in memory. The strings are laid out consecutively in memory, each string terminated by a `0` byte and followed immediately by the next string. !!! TODO: API-REVIEW Change this to an easier to use structure with an array of string pointers. ~~~c typedef struct tm_strings_t { // The number of strings in this data structure. uint32_t count; // The total number of bytes used by the header and all the strings. uint32_t bytes; } tm_strings_t; ~~~
### `struct tm_file_system_watcher_o`
Represents a file system watcher. ~~~c typedef struct tm_file_system_watcher_o { uint64_t opaque; } tm_file_system_watcher_o; ~~~
### `tm_file_system_detailed_watcher_o`
~~~c typedef struct tm_file_system_detailed_watcher_o tm_file_system_detailed_watcher_o; ~~~ Opaque type for a file system watcher that can report detailed `tm_file_system_change_t` changes that happen in the file system.
### `enum tm_file_system_change_action`
Specifies the type of action on the file that was detected by the `tm_file_system_detailed_watcher_o`. !!! WARNING Be careful what "meaning" you infer from the reported action. For example, some software may modify a file by writing a temporary file and then replacing the original with the temporary. This would be reported as a number of `ADDED` and `REMOVED` events, instead of as a `MODIFIED` event. Renames are reported as a `REMOVED` of the old path followed by an `ADDDED` at the new path. ~~~c enum tm_file_system_change_action { TM_FILE_SYSTEM_CHANGE_ACTION__ADDED, TM_FILE_SYSTEM_CHANGE_ACTION__REMOVED, TM_FILE_SYSTEM_CHANGE_ACTION__MODIFIED, }; ~~~
### `struct tm_file_system_change_t`
Represents a change to the file system, detected by the `tm_file_system_detailed_watcher_o`. ~~~c typedef struct tm_file_system_change_t { // The relative path from the watched directory where the changed happened. const char *relative_path; // The change that was detected. enum tm_file_system_change_action action; TM_PAD(4); } tm_file_system_change_t; ~~~
### `struct tm_os_file_system_api`
Interface to the file system. #### `stat()` ~~~c tm_file_stat_t (*stat)(const char *path); ~~~ Returns information about the file at `path`. #### `directory_entries()` ~~~c tm_strings_t *(*directory_entries)(const char *path, struct tm_temp_allocator_i *ta); ~~~ Returns a list of all directory items for the directory `path`. The string list is returned in a pointer allocated by the temporary allocator `ta`. Note that only the file base names are returned in the list. If you want to concatenate them with `path`, you have to do that yourself. Also, note that the list will include the `.` and `..` directories, so you need to filter them out if you do not want to process them. On error, an empty list will be returned. #### `make_directory()` ~~~c bool (*make_directory)(const char *path); ~~~ Creates a new directory at the specified `path`. Returns `true` on success. #### `remove_file()` ~~~c bool (*remove_file)(const char *path); ~~~ Removes the file at the specified `path`. Returns `true` on success. #### `remove_directory()` ~~~c bool (*remove_directory)(const char *path); ~~~ Removes the directory at the specified `path`. If the directory has any content, it will be removed recursively. Returns `true` on success. #### `rename()` ~~~c bool (*rename)(const char *old_name, const char *new_name); ~~~ Renames the file at `old_name` to `new_name`. #### `copy_file()` ~~~c bool (*copy_file)(const char *from, const char *to); ~~~ Copies a single file at `from` to `to`. Returns `true` on success. Overwrites any existing file. #### `getcwd()` ~~~c const char *(*getcwd)(struct tm_temp_allocator_i *ta); ~~~ Returns the current directory, allocated with the specified temp allocator. #### `chdir()` ~~~c bool (*chdir)(const char *path); ~~~ Changes the current directory to the `path`. #### `is_absolute()` ~~~c bool (*is_absolute)(const char *path); ~~~ Returns true if the path is an absolute path. #### `absolute()` ~~~c const char *(*absolute)(const char *path, struct tm_temp_allocator_i *ta); ~~~ Returns the absolute path for the (possibly relative) `path`. !!! NOTE This is a string operation only, it resolves the current working directory and processes any `/.`, `/..` and `//` in the path, but it doesn't resolve symlinks. #### `temp_directory()` ~~~c const char *(*temp_directory)(struct tm_temp_allocator_i *ta); ~~~ Returns the path to the system's temporary directory. #### `create_watcher()` ~~~c tm_file_system_watcher_o (*create_watcher)(const char *subtree_path); ~~~ Creates a file system watcher that watches the specified subtree for changes. (A directory and all its descendents.) #### `any_changes()` ~~~c bool (*any_changes)(tm_file_system_watcher_o watcher); ~~~ Returns true if there were any changes to the subtree watched by `watcher` since the last call to `any_changes()`. #### `destroy_watcher()` ~~~c void (*destroy_watcher)(tm_file_system_watcher_o watcher); ~~~ Destroys a subtree watcher created by `create_watcher()`. #### `create_detailed_watcher()` ~~~c tm_file_system_detailed_watcher_o *(*create_detailed_watcher)(const char *subtree_path); ~~~ Creates a file system watcher that watches a subtree for changes and can return detailed information about those changes as `tm_file_system_change_t` objects. #### `detailed_changes()` ~~~c tm_file_system_change_t *(*detailed_changes)(tm_file_system_detailed_watcher_o *, struct tm_temp_allocator_i *ta); ~~~ Returns a detailed list of the changes that has happened since the last call to `detailed_changes()` as a `carray.inl` of `tm_file_system_change_t` allocated by `ta`. If there were no changes, `NULL` is returned. #### `destroy_detailed_watcher()` ~~~c void (*destroy_detailed_watcher)(tm_file_system_detailed_watcher_o *watcher); ~~~ Destroys a `tm_file_system_detailed_watcher_o` created by `create_detailed_watcher()`. #### `app_folder()` ~~~c const char *(*app_folder)(struct tm_temp_allocator_i *ta); ~~~ On Windows, returns the path to the AppData folder On Linux & OSX, returns the path the home directory. !!! NOTE If an error occurs, the return value is `"./"`.

DLL

### `struct tm_dll_o`
Represents a loaded DLL. ~~~c typedef struct tm_dll_o { // Opaque system handle to DLL. uint64_t handle; // True if DLL handle is valid. bool valid; TM_PAD(7); } tm_dll_o; ~~~
### `struct tm_os_dll_api`
Interface for loading shared libraries. #### `open()` ~~~c tm_dll_o (*open)(const char *path); ~~~ Opens a shared library file. In case of an error, an invalid `tm_dll_o` object will be returned. #### `get()` ~~~c tm_dll_o (*get)(const char *path); ~~~ Gets an already opened shared library file. An invalid `tm_dll_o` object will be returned if the shared library was not loaded. #### `sym()` ~~~c void *(*sym)(tm_dll_o handle, const char *name); ~~~ Looks up and returns a symbol from a shared library. In the case of an error, returns `NULL`. #### `close()` ~~~c void (*close)(tm_dll_o handle); ~~~ Closes a shared library opened by `open()`.

Socket

### `struct tm_socket_o`
Represents an open socket. ~~~c typedef struct tm_socket_o { // Opaque handle to system socket. uint64_t handle; // True if socket is valid. bool valid; TM_PAD(7); } tm_socket_o; ~~~
### `struct tm_socket_address_t`
Represents an address to a socket. ~~~c typedef struct tm_socket_address_t { // IP number. union { uint32_t ip; uint8_t ip_byte[4]; }; // Port. uint32_t port; } tm_socket_address_t; ~~~
### `TM_SOCKET_IP_LOCALHOST`
~~~c #define TM_SOCKET_IP_LOCALHOST ~~~ IP address for `localhost`, for assigning to `ip_byte`: ~~~c const tm_socket_address_t addr = { .ip_byte = TM_SOCKET_IP_LOCALHOST }; ~~~
### `TM_SOCKET_IP_BROADCAST`
~~~c #define TM_SOCKET_IP_BROADCAST ~~~ IP address for broadcasting for assigning to `ip_byte`.
### `enum tm_os_socket_type`
Identifies the socket type. ~~~c enum tm_os_socket_type { TM_OS_SOCKET_TYPE_TCP = 1, TM_OS_SOCKET_TYPE_UDP = 2, }; ~~~
### `enum tm_os_socket_error`
Identifies socket errors. ~~~c enum tm_os_socket_error { // Returned if the operation would cause a non-blocking socket to block. TM_OS_SOCKET_ERROR_WOULD_BLOCK = -1000, // Returned if the socket was closed. TM_OS_SOCKET_ERROR_CLOSED = -1001, // Returned if an invalid socket was used. TM_OS_SOCKET_ERROR_INVALID = -1002, // Used for all other errors. TM_OS_SOCKET_ERROR_OTHER = -1, }; ~~~
### `enum tm_os_socket_connect`
Identifies socket `connect()` results. ~~~c enum tm_os_socket_connect { // Connection is pending (for non-blocking sockets only). You should repeat the connect() // call until a different result is returned. TM_OS_SOCKET_CONNECT_PENDING, // Connection was successfully established. TM_OS_SOCKET_CONNECT_ESTABLISHED, // Connection was refused, failed, or timed out. TM_OS_SOCKET_CONNECT_FAILED }; ~~~
### `enum tm_os_socket_getaddrinfo`
Result of asynchronous `getaddrinfo()` calls. ~~~c enum tm_os_socket_getaddrinfo { // getaddrinfo() is in progress. You should keep calling [[getaddrinfo_result()]] until a // different value is returned. TM_OS_SOCKET_GETADDRINFO_IN_PROGRESS, // getaddrinfo() completed successfully. TM_OS_SOCKET_GETADDRINFO_SUCCESS, // getaddrinfo() completed with an error. TM_OS_SOCKET_GETADDRINFO_ERROR, }; ~~~
### `enum tm_os_socket_option`
Configurable socket options. Note that only the options we find "useful" to change are listed here. We may add more in the future. ~~~c enum tm_os_socket_option { // Disables Nagle's algorithm. When this option is enabled, the socket sends packages as soon as // any data is available. When this option is disabled, the socket waits a little bit to see // if it can send a bigger packet. We usually prefer low latency over high throughput, so this // flag is enabled by default. TM_SOCKET_OPTION__NODELAY, // When this option is set, all socket operations are non-blocking. We set this flag by default // since we typically want to make asynchronous network queries. However, if you are running // your network code on a background thread anyway, you might want to clear this flag. TM_SOCKET_OPTION__NONBLOCK, }; ~~~
### `struct tm_os_socket_api`
Interface to the IP socket layer. #### `init()` ~~~c void (*init)(void); ~~~ Initializes the socket communication layer. You should call this before performing any other socket operation. #### `shutdown()` ~~~c void (*shutdown)(void); ~~~ Shuts down the socket communication layer. #### `socket()` ~~~c tm_socket_o (*socket)(enum tm_os_socket_type type); ~~~ Creates a new socket of the specified type (`TM_OS_SOCkET_TYPE_TCP` or `TM_OS_SOCKET_TYPE_UDP`). If the call fails it will return an invalid socket. You can check for that with the `.valid` field. Sockets created with this function get a default set of options: * `TCP_NODELAY` * `SO_NOSIGPIPE` * `SO_BROADCAST` * `O_NONBLOCK` You can change the options on the socket with `set_option()`. Note that not all options are exposed in the `set_option()` interface. #### `set_option()` ~~~c void (*set_option)(tm_socket_o socket, enum tm_os_socket_option option, bool enabled); ~~~ Enables or disables individual socket options. #### `bind()` ~~~c bool (*bind)(tm_socket_o socket, tm_socket_address_t address); ~~~ Binds the socket to the specified address. Returns `true` if successful. #### `getsockname()` ~~~c bool (*getsockname)(tm_socket_o socket, tm_socket_address_t *address); ~~~ Returns the current address to which the socket is bound. Returns `true` if successful. #### `listen()` ~~~c bool (*listen)(tm_socket_o socket, uint32_t queue_size); ~~~ Sets the socket up to listen for incoming connections. Returns `true` if successful. #### `accept()` ~~~c tm_socket_o (*accept)(tm_socket_o socket, tm_socket_address_t *address); ~~~ Accepts incoming connections to a socket in listen mode. If a connection comes in, its socket will be returned and `address` will be set to the address of the incoming connection. If there is no incoming connection, an invalid socket will be returned. #### `connect()` ~~~c enum tm_os_socket_connect (*connect)(tm_socket_o socket, tm_socket_address_t target); ~~~ Connects the socket to a remote address. Returns one of the `enum tm_os_socket_connect` values. Note that for non-blocking sockets, `TM_OS_SOCKET_CONNECT_PENDING` may be returned. In this case, you should call `connect()` repeatedly until it returns one of the other values. #### `send()` ~~~c int32_t (*send)(tm_socket_o socket, const void *buffer, uint32_t size); ~~~ Sends data to the connected remote socket. Returns the number of transferred bytes on success, otherwise an error code. #### `recv()` ~~~c int32_t (*recv)(tm_socket_o socket, void *buffer, uint32_t size); ~~~ Receives data from the connected remote socket into the `buffer`. Returns the number of bytes received on success, otherwise an error code. #### `sendto()` ~~~c int32_t (*sendto)(tm_socket_o socket, const void *buffer, uint32_t size, tm_socket_address_t target); ~~~ Sends data to the `target`. Returns the number of transferred bytes on success, otherwise an error code. #### `recvfrom()` ~~~c int32_t (*recvfrom)(tm_socket_o socket, void *buffer, uint32_t size, tm_socket_address_t *source); ~~~ Receives data from any sender. The data is received in the `buffer` and sender's address in `source`. Returns the number of transferred bytes on success, otherwise an error code. #### `close()` ~~~c bool (*close)(tm_socket_o socket); ~~~ Closes the `socket`. Returns `true` on success. #### `getaddrinfo()` ~~~c uint32_t (*getaddrinfo)(const char *name, const char *service, tm_socket_address_t *addresses, uint32_t size); ~~~ Resolves a host name based on its name (`"ourmachinery.com"`) and service (`"https"`). Note that the name can be a numeric IP in the form (`"127.0.0.1"`). Returns a list of socket addresses in `addresses`. At most `size` addresses are written to `addresses`. Returns the total number of addresses found for the host (which may be larger than `size`). !!! WARNING This call may block querying DNS servers. Use `getaddrinfo_async()` for a non-blocking call. #### `getaddrinfo_async()` ~~~c void *(*getaddrinfo_async)(const char *name, const char *service); ~~~ Asynchronous version of `getaddrinfo()`. Call `getaddrinfo_async()` to start a query and then repeatedly call `getaddrinfo_result()` with the returned value until you get a different result than `TM_OS_SOCKET_GETADDRINFO_IN_PROGRESS`. #### `getaddrinfo_result()` ~~~c enum tm_os_socket_getaddrinfo (*getaddrinfo_result)(void *query, tm_socket_address_t *addresses, uint32_t *count); ~~~ Returns the result of a `getaddrinfo_async()` call. You should call this repeatedly until you get a different result than `TM_OS_SOCKET_GETADDRINFO_IN_PROGRESS`.

Threading

### `enum tm_os_thread__priority`
Specifies the priority of threads. These pirority levels are translated to OS specific priorities. ~~~c enum tm_os_thread__priority { TM_OS_THREAD__PRIORITY__LOWEST, TM_OS_THREAD__PRIOIRTY__LOW, TM_OS_THREAD__PRIORITY__NORMAL, TM_OS_THREAD__PRIORITY__HIGH, TM_OS_THREAD__PRIORITY__HIGHEST, TM_OS_THREAD__PRIORITY__TIME_CRITICAL, }; ~~~
### `tm_thread_entry_f`
~~~c typedef void tm_thread_entry_f(void *user_data); ~~~ Callback function that acts as entry point for a new thread.
### `tm_fiber_entry_f`
~~~c typedef void tm_fiber_entry_f(void *user_data); ~~~ Callback function that acts as entry point for a new fiber.
### `struct tm_critical_section_o`
Represents a critical section. Note that on OS X, critical sections are not relocatable, i.e., they cannot be passed by value. ~~~c typedef struct tm_critical_section_o { #if defined(TM_OS_WINDOWS) uint64_t opaque; #else uint64_t opaque[8]; #endif } tm_critical_section_o; ~~~
### `struct tm_semaphore_o`
Represents a semaphore. ~~~c typedef struct tm_semaphore_o { uint64_t opaque; } tm_semaphore_o; ~~~
### `struct tm_thread_o`
Represents a thread. ~~~c typedef struct tm_thread_o { uint64_t opaque[2]; } tm_thread_o; ~~~
### `struct tm_fiber_o`
Represents a fiber. ~~~c typedef struct tm_fiber_o { uint64_t opaque; } tm_fiber_o; ~~~
### `struct tm_os_thread_api`
Interface for manipulating threads, mutexes, semaphores, etc.

Critical sections

#### `create_critical_section()` ~~~c void (*create_critical_section)(tm_critical_section_o *cs); ~~~ Creates a new critical section and returns it. #### `enter_critical_section()` ~~~c void (*enter_critical_section)(tm_critical_section_o *cs); ~~~ Enters the critical section `cs`. You can also use the macro `TM_OS_ENTER_CRITICAL_SECTION()` for this, see below. #### `leave_critical_section()` ~~~c void (*leave_critical_section)(tm_critical_section_o *cs); ~~~ Leaves the critical section `cs`. You can also use the macro `TM_OS_LEAVE_CRITICAL_SECTION()` for this, see below. #### `destroy_critical_section()` ~~~c void (*destroy_critical_section)(tm_critical_section_o *cs); ~~~ Destroys a critical section created by `create_critical_section()`.

Semaphores

#### `create_semaphore()` ~~~c tm_semaphore_o (*create_semaphore)(uint32_t initial_count); ~~~ Creates a new semaphore with the `initial_count` and returns it. #### `semaphore_add()` ~~~c void (*semaphore_add)(tm_semaphore_o sem, uint32_t count); ~~~ Adds `count` to the semaphore. #### `semaphore_wait()` ~~~c void (*semaphore_wait)(tm_semaphore_o sem); ~~~ Waits for the semaphore to reach a non-zero value. When it does, decrease the semaphore and continue. #### `semaphore_poll()` ~~~c bool (*semaphore_poll)(tm_semaphore_o sem); ~~~ If the semaphore has a non-zero value, decreases it and returns `true`, otherwise returns false. #### `destroy_semaphore()` ~~~c void (*destroy_semaphore)(tm_semaphore_o sem); ~~~ Destroys a semaphore created by `create_semaphore()`.

Threads

#### `thread_id()` ~~~c uint32_t (*thread_id)(void); ~~~ Gets the ID of the current thread. #### `processor_id()` ~~~c uint32_t (*processor_id)(void); ~~~ Gets the ID of the processor the current thread is running on. #### `create_thread()` ~~~c tm_thread_o (*create_thread)(tm_thread_entry_f *entry, void *user_data, uint32_t stack_size, const char *debug_name); ~~~ Creates a new thread running the `entry` function with `user_data`. `stack_size` specifies the stack size to use for the new thread. `debug_name` is a debug name for the thread that will be visible in debuggers, etc. #### `set_thread_priority()` ~~~c void (*set_thread_priority)(tm_thread_o thread, enum tm_os_thread__priority priority); ~~~ Sets the `priority` of the specified `thread`. #### `wait_for_thread()` ~~~c void (*wait_for_thread)(tm_thread_o thread); ~~~ Blocks and waits for the `thread` to complete running. #### `thread_id_from_tm_thread()` ~~~c uint32_t (*thread_id_from_tm_thread)(tm_thread_o thread); ~~~ Returns the ID of `thread`.

Fibers

#### `convert_thread_to_fiber()` ~~~c tm_fiber_o (*convert_thread_to_fiber)(void *user_data); ~~~ Converts the current thread into a fiber. This is needed before you can call any other fiber functions on the thread. #### `convert_fiber_to_thread()` ~~~c void (*convert_fiber_to_thread)(void); ~~~ Releases any resources allocated by `convert_thread_to_fiber()` and converts the fiber back to a regular thread. After this call, you can't call any other fiber functions on the thread. #### `create_fiber()` ~~~c tm_fiber_o (*create_fiber)(tm_fiber_entry_f *entry, void *user_data, uint32_t stack_size); ~~~ Creates a fiber running the `entry` function with `user_data`. `stack_size` specifies the stack size to use for the new fiber. #### `destroy_fiber()` ~~~c void (*destroy_fiber)(tm_fiber_o fiber); ~~~ Destroys a `fiber` created by `create_fiber()`. #### `switch_to_fiber()` ~~~c void (*switch_to_fiber)(tm_fiber_o fiber); ~~~ Does co-operative multithreading by switching execution to the specified `fiber`. #### `fiber_user_data()` ~~~c void *(*fiber_user_data)(void); ~~~ Returns the user data for the current fiber.

Misc

#### `yield_processor()` ~~~c void (*yield_processor)(void); ~~~ Yields the processor to another thread. You can call this in busy-wait loops to avoid monopolizing the CPU core. #### `sleep()` ~~~c void (*sleep)(double seconds); ~~~ Sleeps the current thread for the specified number of seconds.
### `TM_OS_ENTER_CRITICAL_SECTION()`
~~~c #define TM_OS_ENTER_CRITICAL_SECTION(cs) ~~~ Enters the critical section `cs`. It is recommended that you use the `ENTER/LEAVE` macros instead of directly calling `enter_critical_section()`/ `leave_critical_section()`. When you use these macros you will get a warning about an unused variable `TM_OS_LEAVE_CRITICAL_SECTION_is_missing` if you forget to call `TM_OS_LEAVE_CRITICAL_SECTION(cs)`. !!! NOTE A limitation of these macros is that they can only be used once in a scope (or you will get warnings about multiple definitions of `TM_OS_LEAVE_CRITICAL_SECTION_is_missing`). Thus, if you need to call enter/leave in multiple scopes, you should use the thread API directly.
### `TM_OS_LEAVE_CRITICAL_SECTION()`
~~~c #define TM_OS_LEAVE_CRITICAL_SECTION(cs) ~~~ Leaves a critical section entered by `TM_OS_ENTER_CRITICAL_SECTION()`.

Time

### `struct tm_os_time_api`
Interface for manipulating time. #### `now()` ~~~c tm_clock_o (*now)(void); ~~~ Returns the current time. The time is returned in an opaque format. You shouldn't assume anything about the returned value, only use it as an argument to the `delta()` function. #### `delta()` ~~~c double (*delta)(tm_clock_o to, tm_clock_o from); ~~~ Returns the time passed (in seconds) between the two timestamps `to` and `from`, obtained from calling `now()`. #### `add()` ~~~c tm_clock_o (*add)(tm_clock_o from, double delta); ~~~ Returns the timestamp you get by adding the specified time (in seconds) to the timestamp `from`. #### `file_time_now()` ~~~c tm_file_time_o (*file_time_now)(void); ~~~ Returns the current time as a `tm_file_time_o`. !!! WARNING The time format and clock resolution of `tm_file_time_o` may differ from `tm_clock_o`. #### `file_time_delta()` ~~~c double (*file_time_delta)(tm_file_time_o to, tm_file_time_o from); ~~~ Returns the time passed (in seconds) between the two file timestamps `to` and `from`.

OS Dialogs

### `struct tm_os_dialogs_open_t`
Arguments to `tm_os_dialogs_api->open()`. ~~~c typedef struct tm_os_dialogs_open_t { // List of extensions that can be opened, separated by space, e.g. ("gif png"). const char *extensions; // Description of the files, such as "The Machinery Projects". If not specified, the description // "Files" will be used. const char *description; // If true, more than one file can be selected for opening. bool allow_multi_select; TM_PAD(7); } tm_os_dialogs_open_t; ~~~
### `struct tm_os_dialogs_open_res_t`
Result of `tm_os_dialogs_api->open()`. ~~~c typedef struct tm_os_dialogs_open_res_t { // Number of files that were selected. uint32_t num_files; TM_PAD(4); // Array of filenames. char **files; } tm_os_dialogs_open_res_t; ~~~
### `struct tm_os_dialogs_save_t`
Arguments to `tm_os_dialogs_api->save()`. ~~~c typedef struct tm_os_dialogs_save_t { // Default filename to use for the saved file. const char *default_name; } tm_os_dialogs_save_t; ~~~
### `struct tm_os_dialogs_api`
#### `open()` ~~~c tm_os_dialogs_open_res_t (*open)(const tm_os_dialogs_open_t *s, struct tm_temp_allocator_i *ta); ~~~ Shows the system "Open File..." dialog and lets the user pick a file. Returns the result of the operation. The result is allocated using the supplied temp allocator `ta`. #### `open_folder()` ~~~c char *(*open_folder)(struct tm_temp_allocator_i *ta); ~~~ Shows the system "Open Folder..." dialog and lets the user pick a folder. Returns the path to the picked folder or `NULL` if no folder was picked. The returned path is allocated using the supplied temp allocator `ta`. #### `save()` ~~~c char *(*save)(const tm_os_dialogs_save_t *s, struct tm_temp_allocator_i *ta); ~~~ Shows the system "Save File..." dialog and lets the user pick a file. Returns the filename of the picked file or `NULL` if no file was picked. The returned filename is allocated using the supplied temp allocator `ta`. #### `message_box()` ~~~c void (*message_box)(const char *title, const char *text); ~~~ Displays a message box with a single `OK` button, mostly used for displaying fatal error messages. `title` is the message box caption and `text` is the message to display inside the box. #### `show_count()` ~~~c uint64_t (*show_count)(void); ~~~ Returns the number of OS dialogs that has been shown. This is used to detect if an OS dialog has been shown since the last frame and in that case, reset any held input state (pressed keys, etc).

Info

### `struct tm_os_info_api`
API for obtaining information about the system. #### `num_logical_processors()` ~~~c uint32_t (*num_logical_processors)(void); ~~~ Returns the number of logical processors. #### `avx_support()` ~~~c bool (*avx_support)(void); ~~~ Returns true if the processor supports the AVX instruction set.

Debugger

### `struct tm_os_debugger_api`
`tm_os_debugger_api` is used to interact with the debugger. #### `is_debugger_present()` ~~~c bool (*is_debugger_present)(void); ~~~ Returns `true` if the current process is connected to a debugger. #### `debug_break()` ~~~c void (*debug_break)(void); ~~~ Causes a breakpoint exception to occur and the process to break into the debugger (if any debugger is connected).)

System

### `struct tm_os_system_api`
`tm_os_system_api` is used to interact with system services. #### `open_url()` ~~~c void (*open_url)(const char *url); ~~~ Opens the specified `url` using the default system handler. #### `open_file()` ~~~c bool (*open_file)(const char *file); ~~~ Opens the `file` using the default system application. #### `exe_path()` ~~~c const char *(*exe_path)(const char *argv_0); ~~~ Returns the path to the current executable. `argv_0` should be the argv[0] argument to `main()`. It will be used if we can't determine the path through other means. #### `execute()` ~~~c int (*execute)(const char *command); ~~~ Calls `system()` with the `command` string to execute it using the host environment's command processor. !!! NOTE On Windows, `execute()` will run the command on the command prompt if one is already attached to the current process, otherwise it will run the command silenty. Tt will automatically wrap `command` in quotes if it going to be executed on the command prompt. Because of Windows arcane quoting rules, in addition to quoting individual arguments in the `command` string, the entire string also needs to be quoted. #### `execute_in_background()` ~~~c int (*execute_in_background)(const char *command); ~~~ Same as `execute()` but the process is non-blocking. #### `execute_stdout()` ~~~c char *(*execute_stdout)(const char *command, uint32_t timeout_ms, struct tm_temp_allocator_i *ta, int *exit_code); ~~~ Similar to `execute()` but it returns the `stdout` and `stderr` in a `char *` allocated with the temp allocator `ta`. If `timeout_ms > 0` the call will timeout in the specified number of milliseconds. A `timeout_ms` of 0 means the call never times out. If `exit_code` is non-NULL, it's used to return the exit code. !!! NOTE `execute_stdout()` will automatically wrap `command` in quotes if it going to be executed on the command prompt. Because of Windows arcane quoting rules, in addition to quoting individual arguments in the `command` string, the entire string also needs to be quoted. !!! TODO: API-REVIEW Use seconds as unit instead of milliseconds.

Master API

### `TM_OS_API_NAME`
~~~c #define TM_OS_API_NAME "tm_os_api" ~~~
### `struct tm_os_api`
`tm_os_api` is a "master" API, used to access the APIs for different parts of the OS. #### `virtual_memory` ~~~c struct tm_os_virtual_memory_api *virtual_memory; ~~~ #### `file_io` ~~~c struct tm_os_file_io_api *file_io; ~~~ #### `file_system` ~~~c struct tm_os_file_system_api *file_system; ~~~ #### `dll` ~~~c struct tm_os_dll_api *dll; ~~~ #### `socket` ~~~c struct tm_os_socket_api *socket; ~~~ #### `thread` ~~~c struct tm_os_thread_api *thread; ~~~ #### `time` ~~~c struct tm_os_time_api *time; ~~~ #### `dialogs` ~~~c struct tm_os_dialogs_api *dialogs; ~~~ #### `info` ~~~c struct tm_os_info_api *info; ~~~ #### `debugger` ~~~c struct tm_os_debugger_api *debugger; ~~~ #### `system` ~~~c struct tm_os_system_api *system; ~~~