1
0
Fork 0

fix deadlock by introducing more locks

don't ask
This commit is contained in:
nicoco 2024-04-28 22:12:49 +02:00
parent c48c5baa55
commit a9d65a2cac
3 changed files with 38 additions and 19 deletions

View File

@ -92,13 +92,19 @@ func (w *Gateway) SetLogHandler(h HandleLogFunc) {
w.logger = HandleLogFunc(func(level ErrorLevel, message string) {
// Don't allow other Goroutines from using this thread, as this might lead to concurrent
// use of the GIL, which can lead to crashes.
h(LevelDebug, "Locking OS thread")
runtime.LockOSThread()
defer runtime.UnlockOSThread()
defer UnlockOSThread(h)
h(level, message)
})
}
func UnlockOSThread(h HandleLogFunc) {
h(LevelDebug, "Unlocking OS thread")
runtime.UnlockOSThread()
}
// Init performs initialization procedures for the Gateway, and is expected to be run before any
// calls to [Gateway.Session].
func (w *Gateway) Init() error {

View File

@ -665,12 +665,18 @@ func (s *Session) propagateEvent(kind EventKind, payload *EventPayload) {
// Don't allow other Goroutines from using this thread, as this might lead to concurrent use of
// the GIL, which can lead to crashes.
s.gateway.logger.Debugf("Locking OS Thread (propagateEvent)")
runtime.LockOSThread()
defer runtime.UnlockOSThread()
defer UnlockOSThread2(s)
s.eventHandler(kind, payload)
}
func UnlockOSThread2(s *Session) {
s.gateway.logger.Debugf("Unlocking OS thread (propagateEvent)")
runtime.UnlockOSThread()
}
// HandleEvent processes the given incoming WhatsApp event, checking its concrete type and
// propagating it to the adapter event handler. Unknown or unhandled events are ignored, and any
// errors that occur during processing are logged.

View File

@ -7,7 +7,7 @@ from pathlib import Path
from re import search
from shelve import open
from tempfile import mkstemp
from threading import Lock
from threading import Event, Lock
from typing import Optional, Union, cast
from aiohttp import ClientSession
@ -75,7 +75,7 @@ class Session(BaseSession[str, Recipient]):
self.whatsapp = self.xmpp.whatsapp.NewSession(device)
self._handle_event = make_sync(self.handle_event, self.xmpp.loop)
self.whatsapp.SetEventHandler(self._handle_event)
self._connected = self.xmpp.loop.create_future()
self._connected = Event()
self.user_phone: Optional[str] = None
self._lock = Lock()
@ -86,8 +86,8 @@ class Session(BaseSession[str, Recipient]):
or will re-connect to a previously existing Linked Device session.
"""
self.whatsapp.Login()
self._connected = self.xmpp.loop.create_future()
return await self._connected
await self.xmpp.loop.run_in_executor(None, self._connected.wait)
return self.__get_connected_status_message()
async def logout(self):
"""
@ -104,29 +104,36 @@ class Session(BaseSession[str, Recipient]):
state required for processing by the Gateway itself, and will do minimal processing themselves.
"""
data = whatsapp.EventPayload(handle=ptr)
if event == whatsapp.EventQRCode:
self.log.debug("Handling event %s", data)
if event == whatsapp.EventConnected:
self.contacts.user_legacy_id = data.ConnectedJID
self.user_phone = "+" + data.ConnectedJID.split("@")[0]
self.log.debug("Setting connected")
self._connected.set()
self.log.debug("Connected set")
# this sends the gateway status twice on first login,
# but ensures the gateway status is updated when re-pairing
self.send_gateway_status(self.__get_connected_status_message(), show="chat")
return
elif event == whatsapp.EventQRCode:
self.send_gateway_status("QR Scan Needed", show="dnd")
await self.send_qr(data.QRCode)
return
elif event == whatsapp.EventPair:
self.send_gateway_message(MESSAGE_PAIR_SUCCESS)
with open(str(self.user_shelf_path)) as shelf:
shelf["device_id"] = data.PairDeviceID
elif event == whatsapp.EventConnected:
if self._connected.done():
# On re-pair, Session.login() is not called by slidge core, so
# the status message is not updated
self.send_gateway_status(
self.__get_connected_status_message(), show="chat"
)
else:
self.contacts.user_legacy_id = data.ConnectedJID
self.user_phone = "+" + data.ConnectedJID.split("@")[0]
self._connected.set_result(self.__get_connected_status_message())
return
elif event == whatsapp.EventLoggedOut:
self.logged = False
self._connected.clear()
self.send_gateway_message(MESSAGE_LOGGED_OUT)
self.send_gateway_status("Logged out", show="away")
elif event == whatsapp.EventContact:
return
self.log.debug("Waiting for connected event for %s", data)
await self.xmpp.loop.run_in_executor(None, self._connected.wait)
self.log.debug("Connected! Processing %s", data)
if event == whatsapp.EventContact:
await self.contacts.add_whatsapp_contact(data.Contact)
elif event == whatsapp.EventGroup:
await self.bookmarks.add_whatsapp_group(data.Group)