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.
This commit is contained in:
Po Lu 2021-12-31 09:31:27 +00:00
parent c452ffe4c2
commit d1fde0ab8a

View file

@ -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 @@ class EmacsWindow : public BWindow
~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 @@ class EmacsWindow : public BWindow
if (this->parent)
UnparentAndUnlink ();
child_frame_lock.Unlock ();
}
void
@ -269,10 +279,13 @@ class EmacsWindow : public BWindow
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 @@ class EmacsWindow : public BWindow
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 @@ class EmacsWindow : public BWindow
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 @@ class EmacsWindow : public BWindow
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 @@ class EmacsWindow : public BWindow
}
this->Sync ();
window->LinkChild (this);
child_frame_lock.Unlock ();
}
void
@ -393,6 +420,9 @@ class EmacsWindow : public BWindow
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 @@ class EmacsWindow : public BWindow
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 @@ class EmacsWindow : public BWindow
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 @@ class EmacsWindow : public BWindow
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 @@ class EmacsWindow : public BWindow
{
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 @@ class EmacsWindow : public BWindow
{
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 @@ class EmacsWindow : public BWindow
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 @@ class EmacsWindow : public BWindow
*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 @@ class EmacsWindow : public BWindow
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 @@ class EmacsWindow : public BWindow
{
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 @@ class EmacsWindow : public BWindow
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 @@ class EmacsView : public BView
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 ();