mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 06:43:32 +00:00
bdb9c24cc4
so, and do not exit a monitor twice. (Also do not call Notify when not inside the monitor.)
426 lines
11 KiB
C
426 lines
11 KiB
C
/*
|
|
* lm_wngrp.c: Structures and functions to deal with new LM window groups
|
|
* and multiple LM threads and what not.
|
|
*
|
|
* All blame to Mike McCool (mlm@netscape.com) 2/17/98
|
|
*/
|
|
|
|
#include "lm.h"
|
|
#include "xp.h"
|
|
#include "prclist.h"
|
|
#include "prthread.h"
|
|
#include "prmon.h"
|
|
|
|
#ifdef XP_MAC
|
|
#include "pprthred.h" /* for PR_CreateThreadGCAble */
|
|
#else
|
|
#include "private/pprthred.h"
|
|
#endif
|
|
|
|
/*
|
|
* Notes to self
|
|
*
|
|
* - lm_window_count: do we care that there's only one?
|
|
* - do we need to add a limit to number of threads we spawn()?
|
|
* - JRIEnv: do we need multiple?
|
|
* - JSRuntime: do we need multiple?
|
|
* - Threading changes: impact on debugger?
|
|
* - JS_SetGlobalObject(JSContext) will be important
|
|
* - If the global structure is on the mozilla thread, can other threads
|
|
* creating a new thread group access, or do I have to post an event?
|
|
*
|
|
* ? Rename "MochaDecoder" to "LMWindow"
|
|
* ? Change so that there is only one JSContext
|
|
*/
|
|
|
|
PRMonitor *wingroups_mon;
|
|
LMWindowGroup *wingroups;
|
|
PRMonitor *request_mon;
|
|
|
|
struct ContextListStr {
|
|
ContextList *next;
|
|
ContextList *prev;
|
|
MWContext *context;
|
|
};
|
|
|
|
LMWindowGroup *_lm_NewWindowGroup(int priority);
|
|
|
|
/* Initialize my globals, from the Mozilla thread
|
|
*/
|
|
void lm_InitWindowGroups(void)
|
|
{
|
|
int priority;
|
|
|
|
/* run at slightly lower priority than the mozilla thread */
|
|
priority = PR_GetThreadPriority(PR_CurrentThread());
|
|
PR_ASSERT(priority >= PR_PRIORITY_FIRST && priority <= PR_PRIORITY_LAST);
|
|
|
|
if (priority == PR_PRIORITY_NORMAL)
|
|
priority = PR_PRIORITY_LOW;
|
|
else if (priority == PR_PRIORITY_HIGH)
|
|
priority = PR_PRIORITY_NORMAL;
|
|
else if (priority == PR_PRIORITY_URGENT)
|
|
priority = PR_PRIORITY_HIGH;
|
|
else
|
|
priority = PR_PRIORITY_LOW;
|
|
|
|
wingroups_mon = PR_NewMonitor();
|
|
request_mon = PR_NewMonitor();
|
|
wingroups = NULL;
|
|
wingroups = _lm_NewWindowGroup(priority);
|
|
if(wingroups != NULL) {
|
|
PR_INIT_CLIST(wingroups);
|
|
lm_StartWindowGroup(wingroups);
|
|
} /* else huh?! */
|
|
}
|
|
|
|
/* Create a new window group. Create new context, create new monitor, create
|
|
* new thread, event queue, queue stack, empty context list.
|
|
*/
|
|
LMWindowGroup *lm_NewWindowGroup(void)
|
|
{
|
|
int priority;
|
|
|
|
/* Run at same priority as current thread (which should be a JS
|
|
* thread.
|
|
*/
|
|
priority = PR_GetThreadPriority(PR_CurrentThread());
|
|
PR_ASSERT(priority>=PR_PRIORITY_FIRST && priority<=PR_PRIORITY_LAST);
|
|
return _lm_NewWindowGroup(priority);
|
|
}
|
|
|
|
LMWindowGroup *_lm_NewWindowGroup(int priority)
|
|
{
|
|
LMWindowGroup *newgrp = XP_NEW_ZAP(LMWindowGroup);
|
|
if(newgrp != NULL) {
|
|
newgrp->done = PR_FALSE;
|
|
newgrp->hasLock = PR_FALSE;
|
|
|
|
/* Create a new JS Context for this set of windows.
|
|
* Note: Need to get global runtime lm_runtime from somewhere,
|
|
* and perhaps the LM_STACK_SIZE?
|
|
*/
|
|
/**************************************************** MLM *
|
|
newgrp->js_context = JS_NewContext(lm_runtime, LM_STACK_SIZE);
|
|
if(newgrp->js_context == NULL) {
|
|
XP_DELETE(newgrp);
|
|
return NULL;
|
|
}
|
|
**************************************************** MLM */
|
|
newgrp->js_context = NULL;
|
|
/* JS_SetGCCallback(newgrp->js_context, LM_ShouldRunGC); */
|
|
|
|
newgrp->mw_contexts = XP_NEW_ZAP(ContextList);
|
|
if(newgrp->mw_contexts == NULL) {
|
|
JS_DestroyContext(newgrp->js_context);
|
|
XP_DELETE(newgrp);
|
|
return NULL;
|
|
}
|
|
PR_INIT_CLIST(newgrp->mw_contexts);
|
|
newgrp->mw_contexts->context = NULL;
|
|
newgrp->current_context = NULL;
|
|
|
|
newgrp->queue_stack = XP_NEW_ZAP(QueueStackElement);
|
|
if(!newgrp->queue_stack) {
|
|
JS_DestroyContext(newgrp->js_context);
|
|
XP_DELETE(newgrp->mw_contexts);
|
|
XP_DELETE(newgrp);
|
|
return NULL;
|
|
}
|
|
|
|
/* Do this here so we don't race ourselves in lm_wait_for_events */
|
|
PR_EnterMonitor(wingroups_mon);
|
|
if(wingroups != NULL) {
|
|
PR_APPEND_LINK(newgrp, wingroups);
|
|
}
|
|
PR_ExitMonitor(wingroups_mon);
|
|
|
|
newgrp->waiting_list = NULL;
|
|
|
|
newgrp->owner_monitor = PR_NewMonitor();
|
|
newgrp->queue_monitor = PR_NewMonitor();
|
|
|
|
PR_EnterMonitor(newgrp->owner_monitor);
|
|
newgrp->thread = PR_CreateThreadGCAble(PR_USER_THREAD,
|
|
lm_wait_for_events, newgrp,
|
|
priority, PR_LOCAL_THREAD,
|
|
PR_UNJOINABLE_THREAD, 0);
|
|
newgrp->owner = newgrp->thread;
|
|
newgrp->current_count = 0;
|
|
newgrp->mozWantsLock = PR_FALSE;
|
|
newgrp->mozGotLock = PR_FALSE;
|
|
newgrp->interruptCurrentOp = PR_FALSE;
|
|
newgrp->queue_depth = 0;
|
|
newgrp->queue_count = 0;
|
|
|
|
/* Note: Need a unique identifier for this queue?
|
|
*/
|
|
newgrp->interpret_queue = PR_CreateEventQueue("new_event_queue",
|
|
newgrp->thread);
|
|
newgrp->queue_stack->queue = newgrp->interpret_queue;
|
|
|
|
newgrp->lock_context = NULL;
|
|
newgrp->js_timeout_insertion_point = NULL;
|
|
newgrp->js_timeout_running = NULL;
|
|
newgrp->inputRecurring = 0;
|
|
}
|
|
return newgrp;
|
|
}
|
|
|
|
void lm_StartWindowGroup(LMWindowGroup *grp)
|
|
{
|
|
PR_Notify(grp->owner_monitor);
|
|
PR_ExitMonitor(grp->owner_monitor);
|
|
}
|
|
|
|
void lm_DestroyWindowGroup(LMWindowGroup *grp)
|
|
{
|
|
PR_EnterMonitor(wingroups_mon);
|
|
/* Note: Thread terminates when the thread's main function (in
|
|
* this case, lm_wait_for_events) exits.
|
|
*/
|
|
/************************************ MLM *
|
|
* JS_DestroyContext(grp->js_context);
|
|
************************************ MLM */
|
|
PR_DestroyMonitor(grp->owner_monitor);
|
|
PR_DestroyMonitor(grp->queue_monitor);
|
|
|
|
/* Note: How to destroy an event queue or two?
|
|
*/
|
|
|
|
/* Note: Context list should already be null
|
|
*/
|
|
|
|
PR_REMOVE_LINK(grp);
|
|
XP_DELETE(grp);
|
|
PR_ExitMonitor(wingroups_mon);
|
|
}
|
|
|
|
LMWindowGroup *LM_GetDefaultWindowGroup(MWContext *mwc)
|
|
{
|
|
LMWindowGroup *ans;
|
|
|
|
/* Check to see if this is a frame context. If so, check its parent. */
|
|
if((mwc != NULL) && (mwc->is_grid_cell)) {
|
|
MWContext *grid_parent, *grid_child;
|
|
grid_child = mwc;
|
|
grid_parent = mwc->grid_parent;
|
|
/* Find the root parent. I wonder if I need to add cycle checking. */
|
|
while(grid_parent != NULL) {
|
|
grid_child = grid_parent;
|
|
grid_parent = grid_child->grid_parent;
|
|
}
|
|
if( (ans = lm_MWContextToGroup(grid_child)) != NULL) {
|
|
/* The parent's been found, return its group. */
|
|
return ans;
|
|
} else { /* Else add the parent to the default group,
|
|
* and return that. */
|
|
PR_EnterMonitor(wingroups_mon);
|
|
LM_AddContextToGroup(wingroups, grid_child);
|
|
ans = wingroups;
|
|
PR_ExitMonitor(wingroups_mon);
|
|
return ans;
|
|
}
|
|
}
|
|
PR_EnterMonitor(wingroups_mon);
|
|
ans = wingroups;
|
|
PR_ExitMonitor(wingroups_mon);
|
|
return ans;
|
|
}
|
|
|
|
LMWindowGroup *lm_MWContextToGroup(MWContext *mwc)
|
|
{
|
|
LMWindowGroup *ptr = NULL;
|
|
LMWindowGroup *ans = NULL;
|
|
|
|
PR_EnterMonitor(wingroups_mon);
|
|
|
|
ptr = wingroups;
|
|
|
|
if(lm_GetEntryForContext(wingroups, mwc) != NULL) {
|
|
ans = wingroups;
|
|
PR_ExitMonitor(wingroups_mon);
|
|
return ans;
|
|
}
|
|
|
|
ptr = PR_NEXT_LINK(ptr);
|
|
while(ptr != wingroups) {
|
|
if(lm_GetEntryForContext(ptr, mwc) != NULL) {
|
|
ans = ptr;
|
|
PR_ExitMonitor(wingroups_mon);
|
|
return ans;
|
|
}
|
|
ptr = PR_NEXT_LINK(ptr);
|
|
}
|
|
PR_ExitMonitor(wingroups_mon);
|
|
return NULL;
|
|
}
|
|
|
|
LMWindowGroup *lm_QueueStackToGroup(QueueStackElement *qse)
|
|
{
|
|
LMWindowGroup *ptr = NULL;
|
|
LMWindowGroup *ans = NULL;
|
|
|
|
PR_EnterMonitor(wingroups_mon);
|
|
ptr = wingroups;
|
|
|
|
if(wingroups->queue_stack == qse) {
|
|
ans = wingroups;
|
|
PR_ExitMonitor(wingroups_mon);
|
|
return ans;
|
|
}
|
|
|
|
ptr = PR_NEXT_LINK(ptr);
|
|
while(ptr != wingroups) {
|
|
if(ptr->queue_stack == qse) {
|
|
ans = ptr;
|
|
PR_ExitMonitor(wingroups_mon);
|
|
return ans;
|
|
}
|
|
ptr = PR_NEXT_LINK(ptr);
|
|
}
|
|
PR_ExitMonitor(wingroups_mon);
|
|
return NULL;
|
|
}
|
|
|
|
PREventQueue *LM_MWContextToQueue(MWContext *mwc)
|
|
{
|
|
/* Note: This gets the interpret queue, need to get top queue as well
|
|
*/
|
|
LMWindowGroup *grp = lm_MWContextToGroup(mwc);
|
|
if(grp != NULL) {
|
|
return LM_WindowGroupToQueue(grp);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
PREventQueue *LM_WindowGroupToQueue(LMWindowGroup *lmg)
|
|
{
|
|
return lmg->interpret_queue;
|
|
}
|
|
|
|
ContextList *lm_GetEntryForContext(LMWindowGroup *grp, MWContext *cx)
|
|
{
|
|
ContextList *cxl = grp->mw_contexts;
|
|
ContextList *ans = NULL;
|
|
|
|
if(PR_CLIST_IS_EMPTY(cxl)) {
|
|
return NULL;
|
|
} else {
|
|
ContextList *ptr = PR_NEXT_LINK(cxl);
|
|
while(ptr != cxl) {
|
|
if(ptr->context == cx) {
|
|
ans = ptr;
|
|
break;
|
|
}
|
|
ptr = PR_NEXT_LINK(ptr);
|
|
}
|
|
}
|
|
return ans;
|
|
}
|
|
|
|
void LM_AddContextToGroup(LMWindowGroup *grp, MWContext *cx)
|
|
{
|
|
ContextList *cxl;
|
|
|
|
if(lm_MWContextToGroup(cx) != NULL) {
|
|
/* Hey, why are we adding this stuff twice? */
|
|
XP_ASSERT(0);
|
|
}
|
|
|
|
cxl = XP_NEW_ZAP(ContextList);
|
|
/* Note: failure?!?!?!
|
|
*/
|
|
cxl->context = cx;
|
|
|
|
PR_APPEND_LINK(cxl, grp->mw_contexts);
|
|
}
|
|
|
|
void lm_RemoveContextFromGroup(LMWindowGroup *grp, MWContext *cx);
|
|
|
|
void LM_RemoveContextFromGroup(MWContext *cx)
|
|
{
|
|
LMWindowGroup *grp = lm_MWContextToGroup(cx);
|
|
if(grp) {
|
|
lm_RemoveContextFromGroup(grp, cx);
|
|
}
|
|
}
|
|
|
|
void lm_RemoveContextFromGroup(LMWindowGroup *grp, MWContext *cx)
|
|
{
|
|
if(!PR_CLIST_IS_EMPTY(grp->mw_contexts)) {
|
|
ContextList *entry = lm_GetEntryForContext(grp, cx);
|
|
if(entry != NULL) {
|
|
PR_REMOVE_LINK(entry);
|
|
XP_DELETE(entry);
|
|
}
|
|
}
|
|
if(PR_CLIST_IS_EMPTY(grp->mw_contexts) && (grp != wingroups)) {
|
|
grp->done = PR_TRUE;
|
|
}
|
|
}
|
|
|
|
PRBool LM_IsLocked(LMWindowGroup *grp)
|
|
{
|
|
PRBool ans;
|
|
PR_EnterMonitor(request_mon);
|
|
ans = grp->hasLock;
|
|
PR_ExitMonitor(request_mon);
|
|
return ans;
|
|
}
|
|
|
|
void LM_BeginRequest(LMWindowGroup *grp, JSContext *jsc)
|
|
{
|
|
PR_EnterMonitor(request_mon);
|
|
grp->hasLock = PR_TRUE;
|
|
grp->lock_context = jsc;
|
|
if((JS_GetContextThread(jsc)) != ((intN) grp->thread)) {
|
|
JS_SetContextThread(jsc);
|
|
}
|
|
PR_ExitMonitor(request_mon);
|
|
JS_BeginRequest(jsc);
|
|
}
|
|
|
|
void LM_EndRequest(LMWindowGroup *grp, JSContext *jsc)
|
|
{
|
|
JS_EndRequest(jsc);
|
|
PR_EnterMonitor(request_mon);
|
|
grp->lock_context = NULL;
|
|
grp->hasLock = PR_FALSE;
|
|
PR_ExitMonitor(request_mon);
|
|
}
|
|
|
|
JSBool LM_ShouldRunGC(JSContext *cx, JSGCStatus status)
|
|
{
|
|
JSBool ans = JS_TRUE;
|
|
JSContext *active;
|
|
LMWindowGroup *ptr;
|
|
|
|
if(status != JSGC_BEGIN) {
|
|
return JS_TRUE;
|
|
}
|
|
|
|
PR_EnterMonitor(request_mon);
|
|
if(wingroups->hasLock) {
|
|
active = wingroups->lock_context;
|
|
if(active != cx) {
|
|
ans=JS_FALSE;
|
|
goto bye;
|
|
}
|
|
}
|
|
ptr = PR_NEXT_LINK(wingroups);
|
|
while(ptr != wingroups) {
|
|
if(ptr->hasLock) {
|
|
active = ptr->lock_context;
|
|
if(active != cx) {
|
|
ans=JS_FALSE;
|
|
goto bye;
|
|
}
|
|
}
|
|
ptr = PR_NEXT_LINK(ptr);
|
|
}
|
|
bye:
|
|
PR_ExitMonitor(request_mon);
|
|
return ans;
|
|
}
|