DirectResult fusion_call_init (FusionCall *call, FusionCallHandler handler, void *ctx, const FusionWorld *world) { D_ASSERT( call != NULL ); D_ASSERT( handler != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); memset( call, 0, sizeof(FusionCall) ); call->call_id = ++world->shared->call_ids; /* Store handler, called directly when called by ourself. */ call->handler = handler; call->ctx = ctx; /* Store own fusion id. */ call->fusion_id = fusion_id( world ); /* Keep back pointer to shared world data. */ call->shared = world->shared; return DR_OK; }
DirectResult fusion_ref_init (FusionRef *ref, const char *name, const FusionWorld *world) { D_ASSERT( ref != NULL ); D_ASSERT( name != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_DEBUG_AT( Fusion_Ref, "fusion_ref_init( %p, '%s' )\n", ref, name ? : "" ); ref->multi.id = ++world->shared->ref_ids; ref->multi.builtin.local = 0; ref->multi.builtin.global = 0; fusion_skirmish_init( &ref->multi.builtin.lock, name, world ); ref->multi.builtin.call = NULL; /* Keep back pointer to shared world data. */ ref->multi.shared = world->shared; ref->multi.creator = fusion_id( world ); return DR_OK; }
static ReactionResult reaction_callback( const void *msg_data, void *ctx ) { MSG( "Received message (FusionID %lu, pid %d)!\n", fusion_id( m_world ), getpid() ); return RS_REMOVE; }
static FusionCallHandlerResult dispatch_callback (int caller, int call_arg, void *call_ptr, void *ctx, unsigned int serial, int *ret_val ) { MSG( "Got dispatch callback (FusionID %lu, pid %d)!\n", fusion_id( m_world ), getpid() ); return FCHR_RETURN; }
DirectResult fusion_call_init3 (FusionCall *call, FusionCallHandler3 handler3, void *ctx, const FusionWorld *world) { FusionCallNew call_new; if (direct_log_domain_check( &Fusion_Call )) // avoid call to direct_trace_lookup_symbol_at D_DEBUG_AT( Fusion_Call, "%s( %p, %p <%s>, %p, %p )\n", __FUNCTION__, call, handler3, direct_trace_lookup_symbol_at( handler3 ), ctx, world ); D_ASSERT( call != NULL ); D_ASSERT( handler3 != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); /* Called from others. */ call_new.handler = handler3; call_new.ctx = ctx; while (ioctl( world->fusion_fd, FUSION_CALL_NEW, &call_new )) { switch (errno) { case EINTR: continue; default: break; } D_PERROR ("FUSION_CALL_NEW"); return DR_FAILURE; } memset( call, 0, sizeof(FusionCall) ); /* Store handler, called directly when called by ourself. */ call->handler3 = handler3; call->ctx = ctx; /* Store call and own fusion id. */ call->call_id = call_new.call_id; call->fusion_id = fusion_id( world ); /* Keep back pointer to shared world data. */ call->shared = world->shared; D_DEBUG_AT( Fusion_Call, " -> call id %d\n", call->call_id ); return DR_OK; }
DirectResult coma_thread_init( ComaThread *thread, Coma *coma ) { FusionWorld *world; D_ASSERT( thread != NULL ); D_ASSERT( coma != NULL ); D_DEBUG_AT( Coma_Thread, "%s( %p, %p )\n", __FUNCTION__, thread, coma ); world = coma_world( coma ); thread->shmpool = coma_shmpool( coma ); /* Remember creator. */ thread->fusion_id = fusion_id( world ); D_MAGIC_SET( thread, ComaThread ); return DR_OK; }
int dfb_state_init( CardState *state, CoreDFB *core ) { D_ASSERT( state != NULL ); memset( state, 0, sizeof(CardState) ); state->core = core; state->fusion_id = fusion_id( dfb_core_world(core) ); state->modified = SMF_ALL; state->src_blend = DSBF_SRCALPHA; state->dst_blend = DSBF_INVSRCALPHA; state->render_options = dfb_config->render_options; state->matrix[0] = 0x10000; state->matrix[1] = 0x00000; state->matrix[2] = 0x00000; state->matrix[3] = 0x00000; state->matrix[4] = 0x10000; state->matrix[5] = 0x00000; state->matrix[6] = 0x00000; state->matrix[7] = 0x00000; state->matrix[8] = 0x10000; state->affine_matrix = DFB_TRUE; state->from = CSBR_FRONT; state->to = CSBR_BACK; direct_util_recursive_pthread_mutex_init( &state->lock ); direct_serial_init( &state->dst_serial ); direct_serial_init( &state->src_serial ); direct_serial_init( &state->src_mask_serial ); direct_serial_init( &state->src2_serial ); D_MAGIC_SET( state, CardState ); return 0; }
DirectResult fusion_ref_init (FusionRef *ref, const char *name, const FusionWorld *world) { FusionEntryInfo info; D_ASSERT( ref != NULL ); D_ASSERT( name != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_DEBUG_AT( Fusion_Ref, "fusion_ref_init( %p, '%s' )\n", ref, name ? : "" ); while (ioctl( world->fusion_fd, FUSION_REF_NEW, &ref->multi.id )) { if (errno == EINTR) continue; D_PERROR( "FUSION_REF_NEW" ); return DR_FUSION; } D_DEBUG_AT( Fusion_Ref, " -> new ref %p [%d]\n", ref, ref->multi.id ); info.type = FT_REF; info.id = ref->multi.id; direct_snputs( info.name, name, sizeof(info.name) ); ioctl( world->fusion_fd, FUSION_ENTRY_SET_INFO, &info ); /* Keep back pointer to shared world data. */ ref->multi.shared = world->shared; ref->multi.creator = fusion_id( world ); return DR_OK; }
DFBResult dfb_core_create( CoreDFB **ret_core ) { int ret; #if FUSION_BUILD_MULTI char buf[16]; #endif CoreDFB *core = NULL; CoreDFBShared *shared = NULL; D_ASSERT( ret_core != NULL ); D_ASSERT( dfb_config != NULL ); D_DEBUG_AT( DirectFB_Core, "%s...\n", __FUNCTION__ ); pthread_mutex_lock( &core_dfb_lock ); D_ASSERT( core_dfb == NULL || core_dfb->refs > 0 ); if (core_dfb) { D_MAGIC_ASSERT( core_dfb, CoreDFB ); core_dfb->refs++; *ret_core = core_dfb; pthread_mutex_unlock( &core_dfb_lock ); return DFB_OK; } direct_initialize(); D_INFO( "DirectFB/Core: %s Application Core. ("BUILDTIME") %s%s\n", FUSION_BUILD_MULTI ? "Multi" : "Single", DIRECT_BUILD_DEBUG ? "[ DEBUG ]" : "", DIRECT_BUILD_TRACE ? "[ TRACE ]" : "" ); #if defined(DFB_DYNAMIC_LINKING) && defined(SOPATH) if (!dfb_lib_handle) #ifdef RTLD_GLOBAL dfb_lib_handle = dlopen(SOPATH, RTLD_GLOBAL|RTLD_LAZY); #else /* RTLD_GLOBAL is not defined on OpenBSD */ dfb_lib_handle = dlopen(SOPATH, RTLD_LAZY); #endif #endif ret = dfb_system_lookup(); if (ret) goto error; /* Allocate local core structure. */ core = D_CALLOC( 1, sizeof(CoreDFB) ); if (!core) { ret = D_OOM(); goto error; } core->refs = 1; core->init_handler = direct_thread_add_init_handler( dfb_core_thread_init_handler, core ); #if FUSION_BUILD_MULTI dfb_system_thread_init(); #endif direct_find_best_memcpy(); D_MAGIC_SET( core, CoreDFB ); core_dfb = core; ret = fusion_enter( dfb_config->session, DIRECTFB_CORE_ABI, FER_ANY, &core->world ); if (ret) goto error; core->fusion_id = fusion_id( core->world ); #if FUSION_BUILD_MULTI D_DEBUG_AT( DirectFB_Core, "world %d, fusion id %d\n", fusion_world_index(core->world), core->fusion_id ); snprintf( buf, sizeof(buf), "%d", fusion_world_index(core->world) ); setenv( "DIRECTFB_SESSION", buf, true ); #endif if (dfb_config->sync) { D_INFO( "DirectFB/Core: calling sync()...\n" ); direct_sync(); } if (dfb_config->core_sighandler) direct_signal_handler_add( DIRECT_SIGNAL_ANY, dfb_core_signal_handler, core, &core->signal_handler ); if (fusion_arena_enter( core->world, "DirectFB/Core", dfb_core_arena_initialize, dfb_core_arena_join, core, &core->arena, &ret ) || ret) { ret = ret ? ret : DFB_FUSION; goto error; } shared = core->shared; D_MAGIC_ASSERT( shared, CoreDFBShared ); if (dfb_config->block_all_signals) direct_signals_block_all(); if (dfb_config->deinit_check) direct_cleanup_handler_add( dfb_core_deinit_check, NULL, &core->cleanup_handler ); fusion_skirmish_prevail( &shared->lock ); if (!core->master) { while (!shared->active) fusion_skirmish_wait( &shared->lock, 0 ); } fusion_skirmish_dismiss( &shared->lock ); dfb_font_manager_create( core, &core->font_manager ); *ret_core = core; pthread_mutex_unlock( &core_dfb_lock ); D_DEBUG_AT( DirectFB_Core, "Core successfully created.\n" ); return DFB_OK; error: if (core) { if (core->world) fusion_exit( core->world, false ); if (core->init_handler) direct_thread_remove_init_handler( core->init_handler ); if (core->signal_handler) direct_signal_handler_remove( core->signal_handler ); D_MAGIC_CLEAR( core ); D_FREE( core ); core_dfb = NULL; } pthread_mutex_unlock( &core_dfb_lock ); direct_shutdown(); return ret; }
DirectResult fusion_call_execute3(FusionCall *call, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length) { FusionWorld *world; CallTLS *call_tls; D_DEBUG_AT( Fusion_Call, "%s( %p, flags 0x%x, arg %d, ptr %p, length %u, ret_ptr %p, ret_size %u )\n", __FUNCTION__, call, flags, call_arg, ptr, length, ret_ptr, ret_size ); if (ret_size > FUSION_CALL_RETURN_DATA_MAX) return DR_LIMITEXCEEDED; D_ASSERT( call != NULL ); // if (!call->handler) // return DR_DESTROYED; #if D_DEBUG_ENABLED if (direct_log_domain_check( &Fusion_Call )) // avoid call to direct_trace_lookup_symbol_at D_DEBUG_AT( Fusion_Call, " -> %s\n", direct_trace_lookup_symbol_at( call->handler3 ) ); #endif world = _fusion_world( call->shared ); call_tls = Call_GetTLS( world ); if (call->fusion_id == fusion_id( world ) && (!(flags & FCEF_NODIRECT) || (call_tls->dispatcher))) { FusionCallHandlerResult result; unsigned int execute_length; D_ASSERT( call->handler3 != NULL ); result = call->handler3( call->fusion_id, call_arg, ptr, length, call->ctx, 0, ret_ptr, ret_size, &execute_length ); if (result != FCHR_RETURN) D_WARN( "local call handler returned FCHR_RETAIN, need FCEF_NODIRECT" ); if (ret_length) *ret_length = execute_length; } else { FusionCallExecute3 execute; DirectResult ret = DR_OK; // check whether we can cache this call if (flags & FCEF_QUEUE && fusion_config->call_bin_max_num > 0) { D_ASSERT( flags & FCEF_ONEWAY ); if (call_tls->bins_data_len + length > fusion_config->call_bin_max_data) { ret = fusion_world_flush_calls( world, 0 ); if (ret) return ret; } call_tls->bins[call_tls->bins_num].call_id = call->call_id; call_tls->bins[call_tls->bins_num].call_arg = call_arg; call_tls->bins[call_tls->bins_num].ptr = NULL; call_tls->bins[call_tls->bins_num].length = length; call_tls->bins[call_tls->bins_num].ret_ptr = ret_ptr; call_tls->bins[call_tls->bins_num].ret_length = ret_size; call_tls->bins[call_tls->bins_num].flags = flags | FCEF_FOLLOW; if (length > 0) { call_tls->bins[call_tls->bins_num].ptr = &call_tls->bins_data[call_tls->bins_data_len]; direct_memcpy( &call_tls->bins_data[call_tls->bins_data_len], ptr, length ); call_tls->bins_data_len += length; } call_tls->bins_num++; if (call_tls->bins_num == 1) call_tls->bins_create_ts = direct_clock_get_millis(); else if (call_tls->bins_num >= fusion_config->call_bin_max_num || direct_clock_get_millis() - call_tls->bins_create_ts >= EXECUTE3_BIN_FLUSH_MILLIS) ret = fusion_world_flush_calls( world, 0 ); return ret; } ret = fusion_world_flush_calls( world, 1 ); execute.call_id = call->call_id; execute.call_arg = call_arg; execute.ptr = ptr; execute.length = length; execute.ret_ptr = ret_ptr; execute.ret_length = ret_size; execute.flags = flags | FCEF_RESUMABLE; execute.serial = 0; D_DEBUG_AT( Fusion_Call, " -> ptr %p, length %u\n", ptr, length ); while (ioctl( world->fusion_fd, FUSION_CALL_EXECUTE3, &execute )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR ("Fusion/Call: invalid call (id 0x%08x)\n", call->call_id); return DR_INVARG; case EIDRM: return DR_DESTROYED; default: break; } D_PERROR ("FUSION_CALL_EXECUTE3 (call id 0x%08x, creator %lu)", call->call_id, call->fusion_id ); return DR_FAILURE; } if (ret_length) *ret_length = execute.ret_length; } return DR_OK; }
int main( int argc, char *argv[] ) { DirectResult ret; pid_t child_pid; TestMessage message = {0}; FusionReactor *reactor; Reaction reaction; FusionCall call; DirectFBInit( &argc, &argv ); ret = fusion_enter( -1, 0, FER_MASTER, &m_world ); if (ret) { D_DERROR( ret, "fusion_enter() failed" ); return ret; } MSG( "Entered world %d as master (FusionID %lu, pid %d)\n", fusion_world_index( m_world ), fusion_id( m_world ), getpid() ); reactor = fusion_reactor_new( sizeof(TestMessage), "Test", m_world ); if (!reactor) { D_ERROR( "fusion_reactor_new() failed\n" ); return -1; } MSG( "Attaching to reactor...\n" ); ret = fusion_reactor_attach( reactor, reaction_callback, NULL, &reaction ); if (ret) { D_DERROR( ret, "fusion_reactor_attach() failed" ); return ret; } MSG( ".........FORKING NOW.........\n" ); fusion_world_set_fork_action( m_world, FFA_FORK ); child_pid = fork(); fusion_world_set_fork_action( m_world, FFA_CLOSE ); switch (child_pid) { case -1: D_PERROR( "fork() failed" ); break; case 0: setsid(); MSG( "...arrived after fork() in child (pid %d)..\n", getpid() ); MSG( "..child (FusionID %lu).\n", fusion_id( m_world ) ); usleep( 400000 ); break; default: usleep( 100000 ); MSG( "...returned from fork() in parent, child pid %d.\n", child_pid ); MSG( "Initializing dispatch callback...\n" ); ret = fusion_call_init( &call, dispatch_callback, NULL, m_world ); if (ret) { D_DERROR( ret, "fusion_call_init() failed" ); return ret; } MSG( "Setting dispatch callback...\n" ); ret = fusion_reactor_set_dispatch_callback( reactor, &call, NULL ); if (ret) { D_DERROR( ret, "fusion_reactor_set_dispatch_callback() failed" ); return ret; } MSG( "Sending message via reactor...\n" ); fusion_reactor_dispatch( reactor, &message, true, NULL ); usleep( 100000 ); MSG( "Destroying reactor...\n" ); fusion_reactor_destroy( reactor ); MSG( "...destroyed reactor!\n" ); usleep( 400000 ); MSG( "Freeing reactor...\n" ); fusion_reactor_free( reactor ); MSG( "...freed reactor!\n" ); break; } MSG( "Exiting from world %d (FusionID %lu, pid %d)...\n", fusion_world_index( m_world ), fusion_id( m_world ), getpid() ); fusion_exit( m_world, false ); return 0; }
int main( int argc, char *argv[] ) { DirectResult ret; pid_t child_pid; TestMessage message = {0}; DirectFBInit( &argc, &argv ); ret = fusion_enter( -1, 0, FER_MASTER, &m_world ); if (ret) { D_DERROR( ret, "fusion_enter() failed" ); return ret; } MSG( "Entered world %d as master (FusionID %lu, pid %d)\n", fusion_world_index( m_world ), fusion_id( m_world ), getpid() ); ret = fusion_ref_init( &m_ref, "Test", m_world ); if (ret) { D_DERROR( ret, "fusion_ref_init() failed" ); return -1; } MSG( "Adding local reference...\n" ); fusion_ref_up( &m_ref, false ); m_reactor = fusion_reactor_new( sizeof(TestMessage), "Test", m_world ); if (!m_reactor) { D_ERROR( "fusion_reactor_new() failed\n" ); return -1; } MSG( "Attaching to reactor...\n" ); ret = fusion_reactor_attach( m_reactor, reaction_callback, NULL, &m_reaction ); if (ret) { D_DERROR( ret, "fusion_reactor_attach() failed" ); return ret; } MSG( ".........FORKING NOW.........\n" ); fusion_world_set_fork_action( m_world, FFA_FORK ); child_pid = fork(); fusion_world_set_fork_action( m_world, FFA_CLOSE ); switch (child_pid) { case -1: D_PERROR( "fork() failed" ); break; case 0: setsid(); MSG( "...arrived after fork() in child (pid %d)..\n", getpid() ); MSG( "..child (FusionID %lu).\n", fusion_id( m_world ) ); break; default: usleep( 200000 ); MSG( "...returned from fork() in parent, child pid %d.\n", child_pid ); break; } MSG( "Sending message via reactor...\n" ); fusion_reactor_dispatch( m_reactor, &message, true, NULL ); usleep( 200000 ); MSG( "Removing local reference...\n" ); fusion_ref_down( &m_ref, false ); usleep( 200000 ); MSG( "Exiting from world %d (FusionID %lu, pid %d)...\n", fusion_world_index( m_world ), fusion_id( m_world ), getpid() ); fusion_exit( m_world, false ); return 0; }