sheet eviction when over memory budget
This commit is contained in:
parent
878c6a09a5
commit
f414cd874b
@ -9,6 +9,7 @@
|
|||||||
#include "scratch.h"
|
#include "scratch.h"
|
||||||
#include "atomic.h"
|
#include "atomic.h"
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
GLOBAL struct {
|
GLOBAL struct {
|
||||||
struct atomic_i32 game_thread_shutdown;
|
struct atomic_i32 game_thread_shutdown;
|
||||||
@ -305,7 +306,6 @@ INTERNAL void game_update(void)
|
|||||||
e->valid = true;
|
e->valid = true;
|
||||||
e->rel_xform = XFORM_IDENT;
|
e->rel_xform = XFORM_IDENT;
|
||||||
|
|
||||||
|
|
||||||
entity_enable_prop(e, ENTITY_PROP_CAMERA);
|
entity_enable_prop(e, ENTITY_PROP_CAMERA);
|
||||||
entity_enable_prop(e, ENTITY_PROP_CAMERA_ACTIVE);
|
entity_enable_prop(e, ENTITY_PROP_CAMERA_ACTIVE);
|
||||||
e->camera_follow = player_ent->handle;
|
e->camera_follow = player_ent->handle;
|
||||||
@ -373,6 +373,7 @@ INTERNAL void game_update(void)
|
|||||||
|
|
||||||
/* Clear level */
|
/* Clear level */
|
||||||
case GAME_CMD_KIND_CLEAR_ALL: {
|
case GAME_CMD_KIND_CLEAR_ALL: {
|
||||||
|
logf_info("Clearing level");
|
||||||
for (u64 i = 0; i < entities_array.count; ++i) {
|
for (u64 i = 0; i < entities_array.count; ++i) {
|
||||||
struct entity *ent = &entities_array.entities[i];
|
struct entity *ent = &entities_array.entities[i];
|
||||||
if (ent->valid) {
|
if (ent->valid) {
|
||||||
|
|||||||
200
src/sheet.c
200
src/sheet.c
@ -20,12 +20,10 @@
|
|||||||
|
|
||||||
#define MAX_LOADER_THREADS 4
|
#define MAX_LOADER_THREADS 4
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* Size of cache memory until evictor starts evicting */
|
/* Size of cache memory until evictor starts evicting */
|
||||||
#define CACHE_MEMORY_BUDGET MEGABYTE(8)
|
#define CACHE_MEMORY_BUDGET MEGABYTE(8)
|
||||||
#endif
|
|
||||||
|
|
||||||
/* How long between evictor thread checks */
|
/* How long between evictor thread scans */
|
||||||
#define EVICTOR_CHECK_INTERVAl 0.500
|
#define EVICTOR_CHECK_INTERVAl 0.500
|
||||||
|
|
||||||
/* Time a cache entry spends unused it's considered evictable */
|
/* Time a cache entry spends unused it's considered evictable */
|
||||||
@ -52,8 +50,7 @@ enum cache_node_state {
|
|||||||
CACHE_NODE_STATE_NONE,
|
CACHE_NODE_STATE_NONE,
|
||||||
CACHE_NODE_STATE_QUEUED,
|
CACHE_NODE_STATE_QUEUED,
|
||||||
CACHE_NODE_STATE_WORKING,
|
CACHE_NODE_STATE_WORKING,
|
||||||
CACHE_NODE_STATE_LOADED,
|
CACHE_NODE_STATE_LOADED
|
||||||
CACHE_NODE_STATE_EVICTED
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cache_node {
|
struct cache_node {
|
||||||
@ -63,6 +60,7 @@ struct cache_node {
|
|||||||
struct atomic_u64 last_refcount0_ts; /* Last time that refcount reached 0 */
|
struct atomic_u64 last_refcount0_ts; /* Last time that refcount reached 0 */
|
||||||
|
|
||||||
/* Allocated data */
|
/* Allocated data */
|
||||||
|
u64 memory_usage;
|
||||||
struct arena arena;
|
struct arena arena;
|
||||||
struct sheet *sheet;
|
struct sheet *sheet;
|
||||||
|
|
||||||
@ -86,6 +84,7 @@ struct cache_bucket {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct cache {
|
struct cache {
|
||||||
|
struct atomic_u64 memory_usage;
|
||||||
struct arena arena;
|
struct arena arena;
|
||||||
struct cache_bucket *buckets;
|
struct cache_bucket *buckets;
|
||||||
struct sys_mutex node_pool_mutex;
|
struct sys_mutex node_pool_mutex;
|
||||||
@ -325,6 +324,8 @@ INTERNAL void sheet_load(struct cache_node *n, struct sheet_tag tag)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
arena_set_readonly(&n->arena);
|
arena_set_readonly(&n->arena);
|
||||||
|
n->memory_usage = n->arena.committed;
|
||||||
|
atomic_u64_eval_add(&G.cache.memory_usage, n->memory_usage);
|
||||||
|
|
||||||
logf_info("Finished loading sheet \"%F\" in %F seconds (final size: %F bytes).",
|
logf_info("Finished loading sheet \"%F\" in %F seconds (final size: %F bytes).",
|
||||||
FMT_STR(path),
|
FMT_STR(path),
|
||||||
@ -579,7 +580,6 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sheet_loader_thread_entry_point, arg)
|
|||||||
(UNUSED)arg;
|
(UNUSED)arg;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
sys_mutex_lock(&G.loaders_mutex);
|
sys_mutex_lock(&G.loaders_mutex);
|
||||||
|
|
||||||
if (G.loaders_shutdown) {
|
if (G.loaders_shutdown) {
|
||||||
@ -588,17 +588,11 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sheet_loader_thread_entry_point, arg)
|
|||||||
break;
|
break;
|
||||||
} else if (!G.first_loader_cmd) {
|
} else if (!G.first_loader_cmd) {
|
||||||
/* Wait for work */
|
/* Wait for work */
|
||||||
#if 1
|
|
||||||
sys_condition_variable_wait(&G.loaders_cv, &G.loaders_mutex);
|
sys_condition_variable_wait(&G.loaders_cv, &G.loaders_mutex);
|
||||||
#else
|
|
||||||
sys_mutex_unlock(&G.loaders_mutex);
|
|
||||||
sys_sleep(0.5);
|
|
||||||
sys_mutex_lock(&G.loaders_mutex);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (G.first_loader_cmd) {
|
while (G.first_loader_cmd && !G.loaders_shutdown) {
|
||||||
/* Pull cmd from queue */
|
/* Pull cmd from queue */
|
||||||
struct loader_cmd *cmd = G.first_loader_cmd;
|
struct loader_cmd *cmd = G.first_loader_cmd;
|
||||||
G.first_loader_cmd = cmd->next;
|
G.first_loader_cmd = cmd->next;
|
||||||
@ -626,74 +620,67 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sheet_loader_thread_entry_point, arg)
|
|||||||
* Evictor thread
|
* Evictor thread
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
|
struct evict_node {
|
||||||
|
b32 force_evict;
|
||||||
|
u64 last_used_ts;
|
||||||
|
struct cache_node *cache_node;
|
||||||
|
struct cache_bucket *cache_bucket;
|
||||||
|
struct evict_node *next_unsorted;
|
||||||
|
struct evict_node *next_sorted;
|
||||||
|
struct evict_node *next_evicted;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sheet_evictor_thread_entry_point, arg)
|
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sheet_evictor_thread_entry_point, arg)
|
||||||
{
|
{
|
||||||
(UNUSED)arg;
|
(UNUSED)arg;
|
||||||
|
|
||||||
struct evict_node {
|
|
||||||
b32 evicted;
|
|
||||||
struct cache_node *cache_node;
|
|
||||||
struct evict_node *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct evict_bucket {
|
|
||||||
b32 contains_evicted_node;
|
|
||||||
struct cache_bucket *cache_bucket;
|
|
||||||
struct evict_node *head;
|
|
||||||
struct evict_bucket *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||||
struct evict_bucket *head_evict_bucket = NULL;
|
struct evict_node *head_unsorted = NULL;
|
||||||
b32 any_node_evicted = false;
|
struct evict_node *oldest_sorted = NULL;
|
||||||
|
struct evict_node *head_evicted = NULL;
|
||||||
|
|
||||||
b32 abort_thread_loop = false;
|
b32 abort = false;
|
||||||
sys_mutex_lock(&G.evictor_mutex);
|
sys_mutex_lock(&G.evictor_mutex);
|
||||||
{
|
{
|
||||||
if (G.evictor_shutdown) {
|
|
||||||
/* Thread shutdown */
|
/* Thread shutdown */
|
||||||
abort_thread_loop = true;
|
if (G.evictor_shutdown) {
|
||||||
goto abort_thread_loop;
|
abort = true;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
/* Wait */
|
/* Wait */
|
||||||
sys_condition_variable_wait_time(&G.evictor_cv, &G.evictor_mutex, EVICTOR_CHECK_INTERVAl);
|
sys_condition_variable_wait_time(&G.evictor_cv, &G.evictor_mutex, EVICTOR_CHECK_INTERVAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!G.evictor_shutdown) {
|
||||||
sys_timestamp_t cur_timestamp = sys_timestamp();
|
sys_timestamp_t cur_timestamp = sys_timestamp();
|
||||||
f64 cur_time = sys_timestamp_seconds(cur_timestamp);
|
f64 cur_time = sys_timestamp_seconds(cur_timestamp);
|
||||||
|
|
||||||
|
b32 cache_over_budget = atomic_u64_eval(&G.cache.memory_usage) > CACHE_MEMORY_BUDGET;
|
||||||
|
|
||||||
/* Scan for evictable nodes */
|
/* Scan for evictable nodes */
|
||||||
{
|
{
|
||||||
__profscope(eviction_scan);
|
__profscope(eviction_scan);
|
||||||
|
|
||||||
for (u64 i = 0; i < CACHE_BUCKETS_COUNT; ++i) {
|
for (u64 i = 0; i < CACHE_BUCKETS_COUNT; ++i) {
|
||||||
struct cache_bucket *bucket = &G.cache.buckets[i];
|
struct cache_bucket *bucket = &G.cache.buckets[i];
|
||||||
struct evict_node *head_evict_node = NULL;
|
|
||||||
sys_rw_mutex_lock_shared(&bucket->rw_mutex);
|
sys_rw_mutex_lock_shared(&bucket->rw_mutex);
|
||||||
{
|
{
|
||||||
struct cache_node *n = bucket->first;
|
struct cache_node *n = bucket->first;
|
||||||
while (n) {
|
while (n) {
|
||||||
b32 should_evict_node = false;
|
b32 consider_for_eviction = false;
|
||||||
|
b32 force_evict = false;
|
||||||
if ((atomic_u32_eval(&n->state) == CACHE_NODE_STATE_LOADED) && (atomic_i32_eval(&n->refcount) <= 0)) {
|
if (atomic_u32_eval(&n->state) == CACHE_NODE_STATE_LOADED) {
|
||||||
/* Check usage time */
|
sys_timestamp_t last_used_ts = atomic_u64_eval(&n->last_refcount0_ts);
|
||||||
if (!should_evict_node) {
|
|
||||||
/* TODO: Only evict if over memory budget (in LRU order until under memory budget) */
|
|
||||||
sys_timestamp_t last_used_ts = atomic_u64_raw(&n->last_refcount0_ts);
|
|
||||||
f64 last_used_time = sys_timestamp_seconds(last_used_ts);
|
|
||||||
if (cur_time - last_used_time > EVICTOR_GRACE_PERIOD) {
|
|
||||||
/* Cache entry unused for too long */
|
|
||||||
should_evict_node = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (atomic_i32_eval(&n->refcount) <= 0) {
|
||||||
#if RESOURCE_RELOADING
|
#if RESOURCE_RELOADING
|
||||||
/* Check for file changes for resource reloading */
|
/* Check if file changed for resource reloading */
|
||||||
if (!should_evict_node) {
|
if (!consider_for_eviction) {
|
||||||
should_evict_node = true;
|
|
||||||
struct string path = string_from_cstr_len((char *)n->tag_path, n->tag_path_len);
|
struct string path = string_from_cstr_len((char *)n->tag_path, n->tag_path_len);
|
||||||
if (sys_is_file(path)) {
|
if (!sys_is_file(path)) {
|
||||||
|
consider_for_eviction = true;
|
||||||
|
} else {
|
||||||
struct sys_file file = sys_file_open_read(path);
|
struct sys_file file = sys_file_open_read(path);
|
||||||
struct sys_file_time ft = sys_file_get_time(file);
|
struct sys_file_time ft = sys_file_get_time(file);
|
||||||
sys_file_close(file);
|
sys_file_close(file);
|
||||||
@ -703,50 +690,75 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sheet_evictor_thread_entry_point, arg)
|
|||||||
|
|
||||||
if (MEMCMP_STRUCT(&initial_file_time, ¤t_file_time) != 0) {
|
if (MEMCMP_STRUCT(&initial_file_time, ¤t_file_time) != 0) {
|
||||||
logf_info("Resource file for sheet \"%F\" has changed. Evicting to allow for reloading.", FMT_STR(path));
|
logf_info("Resource file for sheet \"%F\" has changed. Evicting to allow for reloading.", FMT_STR(path));
|
||||||
should_evict_node = true;
|
consider_for_eviction = true;
|
||||||
} else {
|
force_evict = true;
|
||||||
/* File unchanged */
|
|
||||||
should_evict_node = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* Add node to bucket evict list */
|
|
||||||
if (should_evict_node) {
|
/* Check usage time */
|
||||||
|
if (!consider_for_eviction && cache_over_budget && (cur_time - sys_timestamp_seconds(last_used_ts) > EVICTOR_GRACE_PERIOD)) {
|
||||||
|
/* Cache is over budget and node hasn't been referenced in a while */
|
||||||
|
consider_for_eviction = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add node to evict list */
|
||||||
|
if (consider_for_eviction) {
|
||||||
struct evict_node *evict_node = arena_push_zero(scratch.arena, struct evict_node);
|
struct evict_node *evict_node = arena_push_zero(scratch.arena, struct evict_node);
|
||||||
evict_node->cache_node = n;
|
evict_node->cache_node = n;
|
||||||
evict_node->next = head_evict_node;
|
evict_node->cache_bucket = bucket;
|
||||||
head_evict_node = evict_node;
|
evict_node->last_used_ts = last_used_ts;
|
||||||
|
evict_node->force_evict = force_evict;
|
||||||
|
evict_node->next_unsorted = head_unsorted;
|
||||||
|
head_unsorted = evict_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = n->next_hash;
|
n = n->next_hash;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
sys_rw_mutex_unlock_shared(&bucket->rw_mutex);
|
sys_rw_mutex_unlock_shared(&bucket->rw_mutex);
|
||||||
|
|
||||||
/* Add bucket with nodes to evict list */
|
|
||||||
if (head_evict_node) {
|
|
||||||
struct evict_bucket *evict_bucket = arena_push_zero(scratch.arena, struct evict_bucket);
|
|
||||||
evict_bucket->cache_bucket = bucket;
|
|
||||||
evict_bucket->head = head_evict_node;
|
|
||||||
evict_bucket->next = head_evict_bucket;
|
|
||||||
head_evict_bucket = evict_bucket;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove evictable nodes from cache table */
|
/* Sort evict nodes by usage time */
|
||||||
|
{
|
||||||
|
/* TODO: Optimize sort if necessary. Currently O(n^2). */
|
||||||
|
__profscope(eviction_sort);
|
||||||
|
for (struct evict_node *en = head_unsorted; en; en = en->next_unsorted) {
|
||||||
|
sys_timestamp_t ts = en->last_used_ts;
|
||||||
|
struct evict_node *prev = NULL;
|
||||||
|
struct evict_node *next = oldest_sorted;
|
||||||
|
while (next && !(ts <= next->last_used_ts || en->force_evict)) {
|
||||||
|
prev = next;
|
||||||
|
next = next->next_sorted;
|
||||||
|
}
|
||||||
|
if (prev) {
|
||||||
|
prev->next_sorted = en;
|
||||||
|
} else {
|
||||||
|
oldest_sorted = en;
|
||||||
|
}
|
||||||
|
en->next_sorted = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove evictable nodes from cache table until under budget */
|
||||||
{
|
{
|
||||||
__profscope(eviction_cache_removal);
|
__profscope(eviction_cache_removal);
|
||||||
for (struct evict_bucket *eb = head_evict_bucket; eb; eb = eb->next) {
|
for (struct evict_node *en = oldest_sorted; en; en = en->next_sorted) {
|
||||||
struct cache_bucket *bucket = eb->cache_bucket;
|
struct cache_bucket *bucket = en->cache_bucket;
|
||||||
|
struct cache_node *n = en->cache_node;
|
||||||
|
|
||||||
sys_rw_mutex_lock_exclusive(&bucket->rw_mutex);
|
sys_rw_mutex_lock_exclusive(&bucket->rw_mutex);
|
||||||
{
|
{
|
||||||
for (struct evict_node *en = eb->head; en; en = en->next) {
|
if (*atomic_i32_raw(&n->refcount) > 0 || (!en->force_evict && (*atomic_u64_raw(&n->last_refcount0_ts) != en->last_used_ts))) {
|
||||||
struct cache_node *n = en->cache_node;
|
/* Cache node has been referenced since scan, skip eviction. */
|
||||||
/* Check that cache node is still loaded and unreferenced */
|
continue;
|
||||||
if ((atomic_u32_eval(&n->state) == CACHE_NODE_STATE_LOADED) && (atomic_i32_eval(&n->refcount) <= 0)) {
|
}
|
||||||
|
if (en->force_evict || atomic_u64_eval(&G.cache.memory_usage) > CACHE_MEMORY_BUDGET) {
|
||||||
/* Remove from cache table */
|
/* Remove from cache table */
|
||||||
if (n->prev_hash) {
|
if (n->prev_hash) {
|
||||||
n->prev_hash->next_hash = n->next_hash;
|
n->prev_hash->next_hash = n->next_hash;
|
||||||
@ -756,55 +768,47 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sheet_evictor_thread_entry_point, arg)
|
|||||||
if (n->next_hash) {
|
if (n->next_hash) {
|
||||||
n->next_hash->prev_hash = n->prev_hash;
|
n->next_hash->prev_hash = n->prev_hash;
|
||||||
}
|
}
|
||||||
en->evicted = true;
|
atomic_u64_eval_add(&G.cache.memory_usage, -((i64)n->memory_usage));
|
||||||
eb->contains_evicted_node = true;
|
/* Add to evicted list */
|
||||||
any_node_evicted = true;
|
en->next_evicted = head_evicted;
|
||||||
}
|
head_evicted = en;
|
||||||
|
} else {
|
||||||
|
/* Cache is no longer over budget or force evicting, stop iteration */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sys_rw_mutex_unlock_exclusive(&bucket->rw_mutex);
|
sys_rw_mutex_unlock_exclusive(&bucket->rw_mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (any_node_evicted) {
|
if (head_evicted) {
|
||||||
/* Release evicted node memory */
|
/* Release evicted node memory */
|
||||||
|
{
|
||||||
__profscope(eviction_memory_release);
|
__profscope(eviction_memory_release);
|
||||||
for (struct evict_bucket *eb = head_evict_bucket; eb; eb = eb->next) {
|
for (struct evict_node *en = head_evicted; en; en = en->next_evicted) {
|
||||||
if (eb->contains_evicted_node) {
|
|
||||||
for (struct evict_node *en = eb->head; en; en = en->next) {
|
|
||||||
if (en->evicted) {
|
|
||||||
struct cache_node *n = en->cache_node;
|
struct cache_node *n = en->cache_node;
|
||||||
arena_release(&n->arena);
|
arena_release(&n->arena);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add evicted nodes to free list */
|
/* Add evicted nodes to free list */
|
||||||
__profscope(eviction_free_list_append);
|
|
||||||
sys_mutex_lock(&G.cache.node_pool_mutex);
|
sys_mutex_lock(&G.cache.node_pool_mutex);
|
||||||
{
|
{
|
||||||
for (struct evict_bucket *eb = head_evict_bucket; eb; eb = eb->next) {
|
__profscope(eviction_free_list_append);
|
||||||
if (eb->contains_evicted_node) {
|
for (struct evict_node *en = head_evicted; en; en = en->next_evicted) {
|
||||||
for (struct evict_node *en = eb->head; en; en = en->next) {
|
|
||||||
if (en->evicted) {
|
|
||||||
struct cache_node *n = en->cache_node;
|
struct cache_node *n = en->cache_node;
|
||||||
n->next_free = G.cache.node_pool_first_free;
|
n->next_free = G.cache.node_pool_first_free;
|
||||||
G.cache.node_pool_first_free = n;
|
G.cache.node_pool_first_free = n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sys_mutex_unlock(&G.cache.node_pool_mutex);
|
sys_mutex_unlock(&G.cache.node_pool_mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
abort_thread_loop:
|
}
|
||||||
|
|
||||||
sys_mutex_unlock(&G.evictor_mutex);
|
sys_mutex_unlock(&G.evictor_mutex);
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
|
|
||||||
if (abort_thread_loop) {
|
if (abort) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -519,6 +519,8 @@ struct sys_file_time sys_file_get_time(struct sys_file file)
|
|||||||
|
|
||||||
struct sys_file_map sys_file_map_open_read(struct sys_file file)
|
struct sys_file_map sys_file_map_open_read(struct sys_file file)
|
||||||
{
|
{
|
||||||
|
__prof;
|
||||||
|
|
||||||
u64 size = sys_file_get_size(file);
|
u64 size = sys_file_get_size(file);
|
||||||
u8 *base_ptr = NULL;
|
u8 *base_ptr = NULL;
|
||||||
HANDLE map_handle = 0;
|
HANDLE map_handle = 0;
|
||||||
|
|||||||
@ -398,15 +398,13 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(worker_thread_entry_point, thread_data)
|
|||||||
if (G.workers_shutdown) {
|
if (G.workers_shutdown) {
|
||||||
sys_mutex_unlock(&G.mutex);
|
sys_mutex_unlock(&G.mutex);
|
||||||
break;
|
break;
|
||||||
}
|
} else if (!G.scheduled_work_head) {
|
||||||
|
|
||||||
if (!G.scheduled_work_head) {
|
|
||||||
/* Wait for work */
|
/* Wait for work */
|
||||||
sys_condition_variable_wait(&G.cv, &G.mutex);
|
sys_condition_variable_wait(&G.cv, &G.mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do work from top */
|
/* Do work from top */
|
||||||
if (G.scheduled_work_head) {
|
while (G.scheduled_work_head && !G.workers_shutdown) {
|
||||||
struct work *work = G.scheduled_work_head;
|
struct work *work = G.scheduled_work_head;
|
||||||
if (work) {
|
if (work) {
|
||||||
__profscope(work_pool_task);
|
__profscope(work_pool_task);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user