From 60bb74169ede7b08014724731f0c6da52a482538 Mon Sep 17 00:00:00 2001 From: genxium Date: Wed, 25 Jan 2023 23:47:54 +0800 Subject: [PATCH] Fixed libuv resource deallocation. --- frontend/assets/scenes/login.fire | 2 +- frontend/assets/scripts/FindingPlayer.js | 10 +++-- frontend/assets/scripts/Map.js | 7 +--- frontend/assets/scripts/WsSessionMgr.js | 22 ++++++----- frontend/build-templates/.cocos-project.json | 8 ++++ .../runtime-src/Classes/udp_session.cpp | 39 ++++++++++++------- frontend/settings/builder.panel.json | 8 ++-- 7 files changed, 58 insertions(+), 38 deletions(-) create mode 100644 frontend/build-templates/.cocos-project.json diff --git a/frontend/assets/scenes/login.fire b/frontend/assets/scenes/login.fire index 40ebf00..e04355a 100644 --- a/frontend/assets/scenes/login.fire +++ b/frontend/assets/scenes/login.fire @@ -362,7 +362,7 @@ "array": [ 0, 0, - 217.36746944238692, + 209.6693197428241, 0, 0, 0, diff --git a/frontend/assets/scripts/FindingPlayer.js b/frontend/assets/scripts/FindingPlayer.js index 4418d4d..c827068 100644 --- a/frontend/assets/scripts/FindingPlayer.js +++ b/frontend/assets/scripts/FindingPlayer.js @@ -23,7 +23,8 @@ cc.Class({ // LIFE-CYCLE CALLBACKS: onLoad() {}, - init() { + init(mapIns) { + this.mapIns = mapIns; if (null != this.firstPlayerInfoNode) { this.firstPlayerInfoNode.active = false; } @@ -53,9 +54,10 @@ cc.Class({ }, exitBtnOnClick(evt) { - window.clearBoundRoomIdInBothVolatileAndPersistentStorage(); - window.closeWSConnection(constants.RET_CODE.UNKNOWN_ERROR, ""); - cc.director.loadScene('login'); + this.mapIns.hideFindingPlayersGUI(); + cc.log(`FindingPlayers.exitBtnOnClick`); + window.closeWSConnection(constants.RET_CODE.BATTLE_STOPPED, ""); + window.clearLocalStorageAndBackToLoginScene(false); }, updatePlayersInfo(playerMetas) { diff --git a/frontend/assets/scripts/Map.js b/frontend/assets/scripts/Map.js index fa0b309..06f955d 100644 --- a/frontend/assets/scripts/Map.js +++ b/frontend/assets/scripts/Map.js @@ -360,10 +360,6 @@ cc.Class({ if (self.countdownLabel) { self.countdownLabel.string = ""; } - if (self.findingPlayerNode) { - const findingPlayerScriptIns = self.findingPlayerNode.getComponent("FindingPlayer"); - findingPlayerScriptIns.init(); - } if (self.playersInfoNode) { safelyAddChild(self.widgetsAboveAllNode, self.playersInfoNode); } @@ -470,7 +466,7 @@ cc.Class({ self.findingPlayerNode.width = self.canvasNode.width; self.findingPlayerNode.height = self.canvasNode.height; const findingPlayerScriptIns = self.findingPlayerNode.getComponent("FindingPlayer"); - findingPlayerScriptIns.init(); + findingPlayerScriptIns.init(self); self.playersInfoNode = cc.instantiate(self.playersInfoPrefab); @@ -1066,6 +1062,7 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame logout(byClick /* The case where this param is "true" will be triggered within `ConfirmLogout.js`.*/ , shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage) { const self = this; const localClearance = () => { + window.closeWSConnection(constants.RET_CODE.BATTLE_STOPPED, ""); window.clearLocalStorageAndBackToLoginScene(shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage); } diff --git a/frontend/assets/scripts/WsSessionMgr.js b/frontend/assets/scripts/WsSessionMgr.js index 0c4e38c..41c4fc6 100644 --- a/frontend/assets/scripts/WsSessionMgr.js +++ b/frontend/assets/scripts/WsSessionMgr.js @@ -34,7 +34,7 @@ window.closeWSConnection = function(code, reason) { console.log(`"window.clientSession" is already closed or destroyed.`); return; } - console.log(`Closing "window.clientSession" from the client-side.`); + console.log(`Closing "window.clientSession" from the client-side with code=${code}.`); window.clientSession.close(code, reason); } @@ -240,6 +240,12 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) { clientSession.onclose = function(evt) { // [WARNING] The callback "onclose" might be called AFTER the webpage is refreshed with "1001 == evt.code". console.warn(`The WS clientSession is closed: evt=${JSON.stringify(evt)}, evt.code=${evt.code}`); + if (cc.sys.isNative) { + if (mapIns.frameDataLoggingEnabled) { + console.warn(`${mapIns._stringifyRdfIdToActuallyUsedInput()}`); + } + DelayNoMore.UdpSession.closeUdpSession(); + } switch (evt.code) { case constants.RET_CODE.CLIENT_MISMATCHED_RENDER_FRAME: break; @@ -261,7 +267,7 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) { case constants.RET_CODE.MYSQL_ERROR: case constants.RET_CODE.PLAYER_NOT_FOUND: case constants.RET_CODE.PLAYER_CHEATING: - case 1006: // Peer(i.e. the backend) gone unexpectedly + case 1006: // Peer(i.e. the backend) gone unexpectedly, but not working for "cc.sys.isNative" if (mapIns.frameDataLoggingEnabled) { console.warn(`${mapIns._stringifyRdfIdToActuallyUsedInput()}`); } @@ -270,24 +276,20 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) { default: break; } - if (cc.sys.isNative) { - DelayNoMore.UdpSession.closeUdpSession(); - } }; }; window.clearLocalStorageAndBackToLoginScene = function(shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage) { console.warn("+++++++ Calling `clearLocalStorageAndBackToLoginScene`"); + window.clearSelfPlayer(); + if (true != shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage) { + window.clearBoundRoomIdInBothVolatileAndPersistentStorage(); + } if (window.mapIns && window.mapIns.musicEffectManagerScriptIns) { window.mapIns.musicEffectManagerScriptIns.stopAllMusic(); } - window.closeWSConnection(constants.RET_CODE.UNKNOWN_ERROR, ""); - window.clearSelfPlayer(); - if (true != shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage) { - window.clearBoundRoomIdInBothVolatileAndPersistentStorage(); - } cc.director.loadScene('login'); }; diff --git a/frontend/build-templates/.cocos-project.json b/frontend/build-templates/.cocos-project.json new file mode 100644 index 0000000..91b7873 --- /dev/null +++ b/frontend/build-templates/.cocos-project.json @@ -0,0 +1,8 @@ +{ + "engine_version": "2.2.1", + "has_native": true, + "project_type": "js", + "projectName": "DelayNoMore", + "packageName": "org.genxium.delaynomore" +} + diff --git a/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session.cpp b/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session.cpp index 7029525..7e7a465 100644 --- a/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session.cpp +++ b/frontend/build-templates/jsb-link/frameworks/runtime-src/Classes/udp_session.cpp @@ -6,7 +6,8 @@ #include "uv/uv.h" uv_udp_t* udpSocket = NULL; - +uv_thread_t recvTid; +uv_async_t uvLoopStopSig; uv_loop_t* loop = NULL; // Only this loop is used for this simple PoC int const maxPeerCnt = 10; @@ -76,11 +77,25 @@ typedef struct client { short port; }; +void _onUvStopSig(uv_async_t* handle) { + uv_stop(loop); + CCLOG("UDP recv loop is signaled to stop in UvThread"); +} + +void _onWalkCleanup(uv_handle_t* handle, void* data) { + (void)data; + uv_close(handle, NULL); +} + void startRecvLoop(void* arg) { uv_loop_t* l = (uv_loop_t*)arg; - uv_run(l, UV_RUN_DEFAULT); + int uvRunRet1 = uv_run(l, UV_RUN_DEFAULT); + CCLOG("UDP recv loop is ended in UvThread, uvRunRet1=%d", uvRunRet1); + uv_walk(l, _onWalkCleanup, NULL); + int uvRunRet2 = uv_run(l, UV_RUN_DEFAULT); - CCLOG("UDP recv loop is ended!"); + int uvCloseRet = uv_loop_close(l); + CCLOG("UDP recv loop is closed in UvThread, uvRunRet2=%d, uvCloseRet=%d", uvRunRet2, uvCloseRet); } bool DelayNoMore::UdpSession::openUdpSession(int port) { @@ -96,9 +111,9 @@ bool DelayNoMore::UdpSession::openUdpSession(int port) { CCLOG("About to open UDP session at port=%d...", port); loop = uv_loop_new(); uv_udp_init(loop, udpSocket); + uv_async_init(loop, &uvLoopStopSig, _onUvStopSig); uv_udp_recv_start(udpSocket, _allocBuffer, _onRead); - uv_thread_t recvTid; uv_thread_create(&recvTid, startRecvLoop, loop); CCLOG("Finished opening UDP session at port=%d", port); @@ -106,11 +121,6 @@ bool DelayNoMore::UdpSession::openUdpSession(int port) { return true; } -static void _onWalkCleanup(uv_handle_t* handle, void* data) { - (void)data; - uv_close(handle, NULL); -} - bool DelayNoMore::UdpSession::closeUdpSession() { CCLOG("About to close udp session and dealloc all resources..."); @@ -118,17 +128,18 @@ bool DelayNoMore::UdpSession::closeUdpSession() { peerAddrList[i].authKey = -1; // hardcoded for now memset((char*)&peerAddrList[i].sockAddrIn, 0, sizeof(peerAddrList[i].sockAddrIn)); } + uv_async_send(&uvLoopStopSig); // The few if not only guaranteed thread safe utility of libuv :) See http://docs.libuv.org/en/v1.x/async.html#c.uv_async_send + CCLOG("Signaling UvThread to end in GameThread..."); + + uv_thread_join(&recvTid); - uv_stop(loop); - uv_walk(loop, _onWalkCleanup, NULL); - uv_loop_close(loop); free(udpSocket); free(loop); uv_mutex_destroy(&sendLock); uv_mutex_destroy(&recvLock); - CCLOG("Closed udp session and dealloc all resources..."); + CCLOG("Closed udp session and dealloc all resources in GameThread..."); return true; } @@ -141,7 +152,7 @@ void _onSend(uv_udp_send_t* req, int status) { } bool DelayNoMore::UdpSession::upsertPeerUdpAddr(int joinIndex, CHARC* const ip, int port, uint32_t authKey, int roomCapacity, int selfJoinIndex) { - CCLOG("Called by js for joinIndex=%d, ip=%s, port=%d, authKey=%lu; roomCapacity=%d, selfJoinIndex=%d.", joinIndex, ip, port, authKey, roomCapacity, selfJoinIndex); + CCLOG("upsertPeerUdpAddr called by js for joinIndex=%d, ip=%s, port=%d, authKey=%lu; roomCapacity=%d, selfJoinIndex=%d.", joinIndex, ip, port, authKey, roomCapacity, selfJoinIndex); uv_ip4_addr(ip, port, &(peerAddrList[joinIndex - 1].sockAddrIn)); peerAddrList[joinIndex - 1].authKey = authKey; diff --git a/frontend/settings/builder.panel.json b/frontend/settings/builder.panel.json index 6a7c356..2902fe9 100644 --- a/frontend/settings/builder.panel.json +++ b/frontend/settings/builder.panel.json @@ -1,7 +1,7 @@ { "excludeScenes": [], - "packageName": "org.cocos2d.helloworld", - "platform": "web-mobile", + "packageName": "org.genxium.delaynomore", + "platform": "android", "startScene": "2d2f792f-a40c-49bb-a189-ed176a246e49", - "title": "HelloWorld" -} \ No newline at end of file + "title": "DelayNoMore" +}