static void system_cleanup(int flush_async) { /* * Make sure only one thread exits the runtime system. */ if (erts_atomic_inc_read_nob(&exiting) != 1) { /* * Another thread is currently exiting the system; * wait for it to do its job. */ #ifdef ERTS_SMP if (erts_thr_progress_is_managed_thread()) { /* * The exiting thread might be waiting for * us to block; need to update status... */ erts_thr_progress_active(NULL, 0); erts_thr_progress_prepare_wait(NULL); } #endif /* Wait forever... */ while (1) erts_milli_sleep(10000000); } /* No cleanup wanted if ... * 1. we are about to do an abnormal exit * 2. we haven't finished initializing, or * 3. another thread than the main thread is performing the exit * (in threaded non smp case). */ if (!flush_async || !erts_initialized #if defined(USE_THREADS) && !defined(ERTS_SMP) || !erts_equal_tids(main_thread, erts_thr_self()) #endif ) return; #ifdef ERTS_SMP #ifdef ERTS_ENABLE_LOCK_CHECK erts_lc_check_exact(NULL, 0); #endif #endif erts_exit_flush_async(); }
static void system_cleanup(int flush_async) { /* * Make sure only one thread exits the runtime system. */ if (erts_atomic_inc_read_nob(&exiting) != 1) { /* * Another thread is currently exiting the system; * wait for it to do its job. */ #ifdef ERTS_SMP if (erts_thr_progress_is_managed_thread()) { /* * The exiting thread might be waiting for * us to block; need to update status... */ erts_thr_progress_active(NULL, 0); erts_thr_progress_prepare_wait(NULL); } #endif /* Wait forever... */ while (1) erts_milli_sleep(10000000); } /* No cleanup wanted if ... * 1. we are about to do an abnormal exit * 2. we haven't finished initializing, or * 3. another thread than the main thread is performing the exit * (in threaded non smp case). */ if (!flush_async || !erts_initialized #if defined(USE_THREADS) && !defined(ERTS_SMP) || !erts_equal_tids(main_thread, erts_thr_self()) #endif ) return; #ifdef ERTS_SMP #ifdef ERTS_ENABLE_LOCK_CHECK erts_lc_check_exact(NULL, 0); #endif #endif #ifdef HYBRID if (ma_src_stack) erts_free(ERTS_ALC_T_OBJECT_STACK, (void *)ma_src_stack); if (ma_dst_stack) erts_free(ERTS_ALC_T_OBJECT_STACK, (void *)ma_dst_stack); if (ma_offset_stack) erts_free(ERTS_ALC_T_OBJECT_STACK, (void *)ma_offset_stack); ma_src_stack = NULL; ma_dst_stack = NULL; ma_offset_stack = NULL; erts_cleanup_offheap(&erts_global_offheap); #endif #if defined(HYBRID) && !defined(INCREMENTAL) if (global_heap) { ERTS_HEAP_FREE(ERTS_ALC_T_HEAP, (void*) global_heap, sizeof(Eterm) * global_heap_sz); } global_heap = NULL; #endif #ifdef INCREMENTAL erts_cleanup_incgc(); #endif erts_exit_flush_async(); }
/* ** Schedule async_invoke on a worker thread ** NOTE will be syncrounous when threads are unsupported ** return values: ** 0 completed ** -1 error ** N handle value ** arguments: ** ix driver index ** key pointer to secedule queue (NULL means round robin) ** async_invoke function to run in thread ** async_data data to pass to invoke function ** async_free function for relase async_data in case of failure */ long driver_async(ErlDrvPort ix, unsigned int* key, void (*async_invoke)(void*), void* async_data, void (*async_free)(void*)) { ErtsAsync* a; Port* prt; long id; unsigned int qix; #if ERTS_USE_ASYNC_READY_Q Uint sched_id; ERTS_MSACC_PUSH_STATE(); sched_id = erts_get_scheduler_id(); if (!sched_id) sched_id = 1; #else ERTS_MSACC_PUSH_STATE(); #endif prt = erts_drvport2port(ix); if (prt == ERTS_INVALID_ERL_DRV_PORT) return -1; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); a = (ErtsAsync*) erts_alloc(ERTS_ALC_T_ASYNC, sizeof(ErtsAsync)); #if ERTS_USE_ASYNC_READY_Q a->sched_id = sched_id; #endif a->hndl = (DE_Handle*)prt->drv_ptr->handle; a->port = prt->common.id; a->pdl = NULL; a->async_data = async_data; a->async_invoke = async_invoke; a->async_free = async_free; if (!async) id = 0; else { do { id = erts_atomic_inc_read_nob(&async->init.data.id); } while (id == 0); if (id < 0) id *= -1; ASSERT(id > 0); } a->async_id = id; if (key == NULL) { qix = (erts_async_max_threads > 0) ? (id % erts_async_max_threads) : 0; } else { qix = (erts_async_max_threads > 0) ? (*key % erts_async_max_threads) : 0; *key = qix; } #ifdef USE_THREADS if (erts_async_max_threads > 0) { if (prt->port_data_lock) { driver_pdl_inc_refc(prt->port_data_lock); a->pdl = prt->port_data_lock; } async_add(a, async_q(qix)); return id; } #endif ERTS_MSACC_SET_STATE_CACHED(ERTS_MSACC_STATE_PORT); (*a->async_invoke)(a->async_data); ERTS_MSACC_POP_STATE(); if (async_ready(prt, a->async_data)) { if (a->async_free != NULL) { ERTS_MSACC_SET_STATE_CACHED(ERTS_MSACC_STATE_PORT); (*a->async_free)(a->async_data); ERTS_MSACC_POP_STATE(); } } erts_free(ERTS_ALC_T_ASYNC, (void *) a); return id; }