DirectResult fusion_call_execute (FusionCall *call, FusionCallExecFlags flags, int call_arg, void *call_ptr, int *ret_val) { D_DEBUG_AT( Fusion_Call, "%s( %p, 0x%x, %d, %p )\n", __FUNCTION__, call, flags, call_arg, call_ptr ); D_ASSERT( call != NULL ); if (!call->handler) return DR_DESTROYED; D_DEBUG_AT( Fusion_Call, " -> %s\n", direct_trace_lookup_symbol_at( call->handler ) ); if (!(flags & FCEF_NODIRECT) && call->fusion_id == _fusion_id( call->shared )) { int ret; FusionCallHandlerResult result; result = call->handler( _fusion_id( call->shared ), call_arg, call_ptr, call->ctx, 0, &ret ); if (result != FCHR_RETURN) D_WARN( "local call handler returned FCHR_RETAIN, need FCEF_NODIRECT" ); if (ret_val) *ret_val = ret; } else { FusionCallExecute execute; execute.call_id = call->call_id; execute.call_arg = call_arg; execute.call_ptr = call_ptr; execute.flags = flags; while (ioctl( _fusion_fd( call->shared ), FUSION_CALL_EXECUTE, &execute )) { switch (errno) { case EINTR: continue; case EINVAL: // D_ERROR ("Fusion/Call: invalid call\n"); return DR_INVARG; case EIDRM: return DR_DESTROYED; default: break; } D_PERROR ("FUSION_CALL_EXECUTE"); return DR_FAILURE; } if (ret_val) *ret_val = execute.ret_val; } return DR_OK; }
DirectResult fusion_call_execute (FusionCall *call, FusionCallExecFlags flags, int call_arg, void *call_ptr, int *ret_val) { DirectResult ret = DR_OK; FusionWorld *world; FusionCallMessage msg; struct sockaddr_un addr; D_ASSERT( call != NULL ); if (!call->handler) return DR_DESTROYED; if (!(flags & FCEF_NODIRECT) && call->fusion_id == _fusion_id( call->shared )) { int ret; FusionCallHandlerResult result; result = call->handler( _fusion_id( call->shared ), call_arg, call_ptr, call->ctx, 0, &ret ); if (result != FCHR_RETURN) D_WARN( "local call handler returned FCHR_RETAIN, need FCEF_NODIRECT" ); if (ret_val) *ret_val = ret; return DR_OK; } world = _fusion_world( call->shared ); msg.type = FMT_CALL; msg.caller = world->fusion_id; msg.call_id = call->call_id; msg.call_arg = call_arg; msg.call_ptr = call_ptr; msg.handler = call->handler; msg.ctx = call->ctx; msg.flags = flags; if (flags & FCEF_ONEWAY) { /* Invalidate serial. */ msg.serial = -1; /* Send message. */ addr.sun_family = AF_UNIX; snprintf( addr.sun_path, sizeof(addr.sun_path), "/tmp/.fusion-%d/%lx", call->shared->world_index, call->fusion_id ); ret = _fusion_send_message( world->fusion_fd, &msg, sizeof(msg), &addr ); } else { int fd; socklen_t len; int err; fd = socket( PF_LOCAL, SOCK_RAW, 0 ); if (fd < 0) { D_PERROR( "Fusion/Call: Error creating local socket!\n" ) ; return DR_IO; } /* Set close-on-exec flag. */ fcntl( fd, F_SETFD, FD_CLOEXEC ); addr.sun_family = AF_UNIX; len = snprintf( addr.sun_path, sizeof(addr.sun_path), "/tmp/.fusion-%d/call.%x.", fusion_world_index( world ), call->call_id ); /* Generate call serial (socket address is based on it). */ for (msg.serial = 0; msg.serial <= 0xffffff; msg.serial++) { snprintf( addr.sun_path+len, sizeof(addr.sun_path)-len, "%x", msg.serial ); err = bind( fd, (struct sockaddr*)&addr, sizeof(addr) ); if (err == 0) { chmod( addr.sun_path, 0660 ); /* Change group, if requested. */ if (fusion_config->shmfile_gid != (gid_t)-1) chown( addr.sun_path, -1, fusion_config->shmfile_gid ); break; } } if (err < 0) { D_PERROR( "Fusion/Call: Error binding local socket!\n" ); close( fd ); return DR_IO; } /* Send message. */ snprintf( addr.sun_path, sizeof(addr.sun_path), "/tmp/.fusion-%d/%lx", call->shared->world_index, call->fusion_id ); ret = _fusion_send_message( fd, &msg, sizeof(msg), &addr ); if (ret == DR_OK) { FusionCallReturn callret; /* Wait for reply. */ ret = _fusion_recv_message( fd, &callret, sizeof(callret), NULL ); if (ret == DR_OK) { if (ret_val) *ret_val = callret.val; } } len = sizeof(addr); if (getsockname( fd, (struct sockaddr*)&addr, &len ) == 0) unlink( addr.sun_path ); close( fd ); } return ret; }
DirectResult fusion_call_execute2(FusionCall *call, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, int *ret_val) { D_DEBUG_AT( Fusion_Call, "%s( %p, flags 0x%x, arg %d, %p, length %u )\n", __FUNCTION__, call, flags, call_arg, ptr, length ); D_ASSERT( call != NULL ); // if (!call->handler) // return DR_DESTROYED; 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->handler ) ); if (!(flags & FCEF_NODIRECT) && call->fusion_id == _fusion_id( call->shared )) { int ret; FusionCallHandlerResult result; result = call->handler( call->fusion_id, call_arg, ptr, call->ctx, 0, &ret ); if (result != FCHR_RETURN) D_WARN( "local call handler returned FCHR_RETAIN, need FCEF_NODIRECT" ); if (ret_val) *ret_val = ret; } else { FusionCallExecute2 execute; execute.call_id = call->call_id; execute.call_arg = call_arg; execute.ptr = ptr; execute.length = length; execute.flags = flags | FCEF_RESUMABLE; execute.serial = 0; fusion_world_flush_calls( _fusion_world( call->shared ), 1 ); while (ioctl( _fusion_fd( call->shared ), FUSION_CALL_EXECUTE2, &execute )) { switch (errno) { case EINTR: continue; case EINVAL: // D_ERROR ("Fusion/Call: invalid call\n"); return DR_INVARG; case EIDRM: return DR_DESTROYED; default: break; } D_PERROR ("FUSION_CALL_EXECUTE2 (call id 0x%08x, creator %lu)", call->call_id, call->fusion_id ); return DR_FAILURE; } if (ret_val) *ret_val = execute.ret_val; } return DR_OK; }
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) { 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; D_DEBUG_AT( Fusion_Call, " -> %s\n", direct_trace_lookup_symbol_at( call->handler3 ) ); if (!(flags & FCEF_NODIRECT) && call->fusion_id == _fusion_id( call->shared )) { 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; 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; D_DEBUG_AT( Fusion_Call, " -> ptr %p, length %u\n", ptr, length ); while (ioctl( _fusion_fd( call->shared ), FUSION_CALL_EXECUTE3, &execute )) { switch (errno) { case EINTR: continue; case EINVAL: // D_ERROR ("Fusion/Call: invalid call\n"); return DR_INVARG; case EIDRM: return DR_DESTROYED; default: break; } D_PERROR ("FUSION_CALL_EXECUTE3"); return DR_FAILURE; } if (ret_length) *ret_length = execute.ret_length; } return DR_OK; }