From d1fde0ab8ae53b684ff4ba858f1e270bc3ba9db6 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Fri, 31 Dec 2021 09:31:27 +0000 Subject: [PATCH] Use a single global lock for the child frame state on Haiku Each BWindows (and various system callbacks) runs in a separate thread, so there are very complicated locking semantics that used to be handled manually. This changes child frame state to use a single global lock, which makes things much easier. * src/haiku_support.cc (child_frame_lock): New variable. (class EmacsWindow): (~EmacsWindow): (Unparent): (ParentTo): (MoveChild): (FrameMoved): (EmacsHide): (EmacsShow): (GetParentWidthHeight): (OffsetChildRect): (MakeFullscreen): (SetUpDoubleBuffering): Use a single lock for controlling access to child frame state. --- src/haiku_support.cc | 75 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 3 deletions(-) diff --git a/src/haiku_support.cc b/src/haiku_support.cc index d211f1157d3..66b0e519b07 100644 --- a/src/haiku_support.cc +++ b/src/haiku_support.cc @@ -85,6 +85,13 @@ static key_map *key_map = NULL; static char *key_chars = NULL; static BLocker key_map_lock; +/* The locking semantics of BWindows running in multiple threads are + so complex that child frame state (which is the only state that is + shared between different BWindows at runtime) does best with a + single global lock. */ + +static BLocker child_frame_lock; + extern "C" { extern _Noreturn void emacs_abort (void); @@ -247,6 +254,8 @@ public: ~EmacsWindow () { + if (!child_frame_lock.Lock ()) + gui_abort ("Failed to lock child frame state lock"); struct child_frame *next; for (struct child_frame *f = subset_windows; f; f = next) { @@ -257,6 +266,7 @@ public: if (this->parent) UnparentAndUnlink (); + child_frame_lock.Unlock (); } void @@ -269,10 +279,13 @@ public: void UpwardsSubsetChildren (EmacsWindow *w) { + if (!child_frame_lock.Lock ()) + gui_abort ("Failed to lock child frame state lock"); UpwardsSubset (w); for (struct child_frame *f = subset_windows; f; f = f->next) f->window->UpwardsSubsetChildren (w); + child_frame_lock.Unlock (); } void @@ -285,15 +298,20 @@ public: void UpwardsUnSubsetChildren (EmacsWindow *w) { + if (!child_frame_lock.Lock ()) + gui_abort ("Failed to lock child frame state lock"); UpwardsUnSubset (w); for (struct child_frame *f = subset_windows; f; f = f->next) f->window->UpwardsUnSubsetChildren (w); + child_frame_lock.Unlock (); } void Unparent (void) { + if (!child_frame_lock.Lock ()) + gui_abort ("Failed to lock child frame state lock"); this->SetFeel (B_NORMAL_WINDOW_FEEL); UpwardsUnSubsetChildren (parent); this->RemoveFromSubset (this); @@ -303,13 +321,17 @@ public: fullscreen_p = 0; MakeFullscreen (1); } + child_frame_lock.Unlock (); } void UnparentAndUnlink (void) { + if (!child_frame_lock.Lock ()) + gui_abort ("Failed to lock child frame state lock"); this->parent->UnlinkChild (this); this->Unparent (); + child_frame_lock.Unlock (); } void @@ -337,6 +359,9 @@ public: void ParentTo (EmacsWindow *window) { + if (!child_frame_lock.Lock ()) + gui_abort ("Failed to lock child frame state lock"); + if (this->parent) UnparentAndUnlink (); @@ -352,6 +377,8 @@ public: } this->Sync (); window->LinkChild (this); + + child_frame_lock.Unlock (); } void @@ -393,6 +420,9 @@ public: MoveChild (EmacsWindow *window, int xoff, int yoff, int weak_p) { + if (!child_frame_lock.Lock ()) + gui_abort ("Failed to lock child frame state lock"); + for (struct child_frame *f = subset_windows; f; f = f->next) { @@ -402,10 +432,13 @@ public: f->yoff = yoff; if (!weak_p) DoMove (f); + + child_frame_lock.Unlock (); return; } } + child_frame_lock.Unlock (); gui_abort ("Trying to move a child frame that doesn't exist"); } @@ -606,9 +639,14 @@ public: haiku_write (MOVE_EVENT, &rq); + if (!child_frame_lock.Lock ()) + gui_abort ("Failed to lock child frame state lock"); + for (struct child_frame *f = subset_windows; f; f = f->next) DoMove (f); + + child_frame_lock.Unlock (); BWindow::FrameMoved (newPosition); } @@ -623,10 +661,14 @@ public: void EmacsMoveTo (int x, int y) { + if (!child_frame_lock.Lock ()) + gui_abort ("Failed to lock child frame state lock"); + if (!this->parent) this->MoveTo (x, y); else this->parent->MoveChild (this, x, y, 0); + child_frame_lock.Unlock (); } bool @@ -654,9 +696,14 @@ public: { if (this->IsHidden ()) return; + if (!child_frame_lock.Lock ()) + gui_abort ("Failed to lock child frame state lock"); + Hide (); if (this->parent) UpwardsUnSubsetChildren (this->parent); + + child_frame_lock.Unlock (); } void @@ -664,11 +711,17 @@ public: { if (!this->IsHidden ()) return; + + if (!child_frame_lock.Lock ()) + gui_abort ("Failed to lock child frame state lock"); + if (this->parent) shown_flag = 1; Show (); if (this->parent) UpwardsSubsetChildren (this->parent); + + child_frame_lock.Unlock (); } void @@ -719,6 +772,9 @@ public: void GetParentWidthHeight (int *width, int *height) { + if (!child_frame_lock.Lock ()) + gui_abort ("Failed to lock child frame state lock"); + if (parent) { *width = parent->Frame ().Width (); @@ -730,11 +786,16 @@ public: *width = s.Frame ().Width (); *height = s.Frame ().Height (); } + + child_frame_lock.Unlock (); } void OffsetChildRect (BRect *r, EmacsWindow *c) { + if (!child_frame_lock.Lock ()) + gui_abort ("Failed to lock child frame state lock"); + for (struct child_frame *f; f; f = f->next) if (f->window == c) { @@ -742,9 +803,11 @@ public: r->bottom -= f->yoff; r->left -= f->xoff; r->right -= f->xoff; + child_frame_lock.Unlock (); return; } + child_frame_lock.Lock (); gui_abort ("Trying to calculate offsets for a child frame that doesn't exist"); } @@ -753,8 +816,8 @@ public: { BScreen screen (this); - if (!screen.IsValid ()) - gui_abort ("Trying to make a window fullscreen without a screen"); + if (!screen.IsValid ()) + gui_abort ("Trying to make a window fullscreen without a screen"); if (make_fullscreen_p == fullscreen_p) return; @@ -768,9 +831,15 @@ public: flags |= B_NOT_MOVABLE | B_NOT_ZOOMABLE; pre_fullscreen_rect = Frame (); + + if (!child_frame_lock.Lock ()) + gui_abort ("Failed to lock child frame state lock"); + if (parent) parent->OffsetChildRect (&pre_fullscreen_rect, this); + child_frame_lock.Unlock (); + int w, h; EmacsMoveTo (0, 0); GetParentWidthHeight (&w, &h); @@ -1065,7 +1134,7 @@ public: if (looper_locked_count) { if (!offscreen_draw_bitmap_1->Lock ()) - gui_abort ("Failed to lock bitmap after double buffering was set up."); + gui_abort ("Failed to lock bitmap after double buffering was set up"); } UnlockLooper (); -- 2.39.2