/************************************************************************
* schedule.cpp *
* Main task scheduler for Borg. This class is central to the workings *
* of the secondary thread, and to the calls which are passed back and *
* forth to the secondary thread. When Borg decides it is going to do *
* something it is added to a list of things to do, along with a *
* priority for doing it. Like updating the main window is more *
* important than naming a location. The scheduler then manages the *
* queue of items to be processed, and calls each in turn. The queue can *
* be temporarily stopped for low priority items (lower than userrequest *
* priority), this is to enable many of the primary thread dialog boxes *
* to work whilst maintaining window updates and changes *
* Accessing the task list should be covered by critical sections, since *
* either thread can access the list. The other place that critical *
* sections are heavily used is in the display of the main window, and *
* the buffer generation for the main window. *
************************************************************************/
#include <windows.h>
#include "schedule.h"
#include "xref.h"
#include "gname.h"
#include "disasm.h"
#include "data.h"
#include "dasm.h"
#include "range.h"
#include "debug.h"
/************************************************************************
* constructor *
* - simply sets up the thread pause/stop request status *
************************************************************************/
schedule::schedule() {
// threadpause=false;
// threadstopped=true;
}
/************************************************************************
* destructor *
* - currently null function *
************************************************************************/
schedule::~schedule() { }
/************************************************************************
* addtask *
* - this adds a task to the queue. This function has to be very careful *
* as it can potentially be called by either thread at any time, and *
* so could be called from both threads at almost the same time. *
* So there is a critical section for manipulating the queue of tasks. *
* - added tasktype tt and moved tnumt whilst commenting this function *
* Borg v2.21 for safety! *
************************************************************************/
void schedule::addtask(tasktype ttype,priority p,lptr loc,char *comment) {
taskitem *titem;
static dword tnumt=0;
tasktype tt;
// limit window updates added to queue - could be called many times by disasm.
if (ttype==windowupdate) {
// EnterCriticalSection(&cs);
titem=peekfirst();
if (titem) tt=titem->ttype;
else tt=tasktype_null; // zero
// LeaveCriticalSection(&cs);
if (tt==windowupdate) return;
}
titem=new taskitem;
titem->ttype=ttype;
titem->p=p;
titem->addr=loc;
if (comment) titem->comment=strdup(comment);
// EnterCriticalSection(&cs);
titem->tnum=tnumt;
tnumt++;
addto(titem);
// LeaveCriticalSection(&cs);
}
/************************************************************************
* compare function *
* - the task list is stored in priority order, and then using a uid *
* generated during the add function *
************************************************************************/
int schedule::compare(taskitem *i,taskitem *j) {
if (i->p==j->p) {
if(i->tnum==j->tnum) return 0;
if(i->tnum>j->tnum) return 1;
return -1;
}
if (i->p>j->p) return 1;
return -1;
}
/************************************************************************
* delete function *
* - overrides the standard listitem deletion function *
************************************************************************/
void schedule::delfunc(taskitem *i) {
if (i->comment) delete i->comment;
delete i;
}
/************************************************************************
* process *
* - here we take the item at the front of the task queue and process it *
* - if the queue has been requested to hold then we only process high *
* priority items *
* - more thread safety code added v 2.21 during commenting and closer *
* examination *
************************************************************************/
bool schedule::process(void) {
// returns false if nothing to do, thus message loop can call WaitMessage()
taskitem *task;
// bool done;
bool procdany;
priority q;
// done=false;
procdany=false;
// threadstopped=false;
// do{
// our checks for pausing the threads must be thread safe
// accessing the task list must be in a critical section
// EnterCriticalSection(&cs);
task=peekfirst();
if (task) q=task->p;
else q=priority_null; // zero
// LeaveCriticalSection(&cs);
// if (q>priority_userrequest) {
// while (threadpause) {
// threadstopped=true;
// EnterCriticalSection(&cs);
// task=peekfirst();
// if (task) q=task->p;
// else q=priority_null; // zero
// LeaveCriticalSection(&cs);
// if (q<priority_userrequest) break;
// Sleep(0);
// }
// }
// threadstopped=false;
// EnterCriticalSection(&cs);
// note: processqueue detaches the task from the list and gives it to us
task=processqueue();
// LeaveCriticalSection(&cs);
if (!task) return false;
StatusMessageNItems(numlistitems());
procdany=true;
// note - if the routine to be called does not delete any task->comment string then
// it is up to the code here to do it.
switch(task->ttype) {
case dis_code:
#ifdef DEBUG
DebugMessage("Scheduler: Disassembling Code at: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disblock(task->addr);
break;
case dis_exportcode:
#ifdef DEBUG
DebugMessage("Scheduler: Disassembling Export Code at: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disexportblock(task->addr);
break;
case user_makecode:
#ifdef DEBUG
DebugMessage("Scheduler: User Make Code");
#endif
cvd->makecode();
break;
case user_undefineline:
#ifdef DEBUG
DebugMessage("Scheduler: User Undefine Line");
#endif
dsm->undefineline();
break;
case user_undefinelines:
#ifdef DEBUG
DebugMessage("Scheduler: User Undefine Lines");
#endif
dsm->undefinelines();
break;
case user_undefinelines_long:
#ifdef DEBUG
DebugMessage("Scheduler: User Undefine Lines Long");
#endif
dsm->undefinelines_long();
break;
case user_jumpback:
#ifdef DEBUG
DebugMessage("Scheduler: User Jump Back");
#endif
cvd->jumpback();
break;
case user_jumpto:
#ifdef DEBUG
DebugMessage("Scheduler: User Jump To");
#endif
cvd->jumpto(true);
break;
case user_jumptoarg2:
#ifdef DEBUG
DebugMessage("Scheduler: User Jump To (arg2)");
#endif
cvd->jumpto(false);
break;
case user_jumptoaddr:
#ifdef DEBUG
DebugMessage("Scheduler: User Jump To Addr");
#endif
cvd->follow(task->addr);
break;
case windowupdate:
cvd->updatewindow();
break;
case scrolling:
cvd->scroller(task->addr.offs);
break;
case vthumbposition:
cvd->vertsetpos(task->addr.offs);
break;
// case hthumbposition:
// cvd->horizscrollto(task->addr.offs);
// break;
// case hscroll: // amount
// cvd->horizscroll(task->addr.offs);
// break;
case user_makedword:
#ifdef DEBUG
DebugMessage("Scheduler: User Make dword");
#endif
cvd->makedword();
break;
case user_makesingle:
#ifdef DEBUG
DebugMessage("Scheduler: User Make single real");
#endif
cvd->makesingle();
break;
case user_makedouble:
#ifdef DEBUG
DebugMessage("Scheduler: User Make double real");
#endif
cvd->makedouble();
break;
case user_makelongdouble:
#ifdef DEBUG
DebugMessage("Scheduler: User Make long double real");
#endif
cvd->makelongdouble();
break;
case user_makeword:
#ifdef DEBUG
DebugMessage("Scheduler: User Make Word");
#endif
cvd->makeword();
break;
case user_makestring:
#ifdef DEBUG
DebugMessage("Scheduler: User Make String");
#endif
cvd->makestring();
break;
case user_pascalstring:
#ifdef DEBUG
DebugMessage("Scheduler: User Pascal String");
#endif
cvd->pascalstring();
break;
case user_ucstring:
#ifdef DEBUG
DebugMessage("Scheduler: User Unicode C String");
#endif
cvd->ucstring();
break;
case user_upstring:
#ifdef DEBUG
DebugMessage("Scheduler: User Unicode Pascal String");
#endif
cvd->upstring();
break;
case user_dosstring:
#ifdef DEBUG
DebugMessage("Scheduler: User DOS String");
#endif
cvd->dosstring();
break;
case user_generalstring:
#ifdef DEBUG
DebugMessage("Scheduler: User General String");
#endif
cvd->generalstring();
break;
case user_argoverdec:
#ifdef DEBUG
DebugMessage("Scheduler: User Argument Override Decimal");
#endif
cvd->argoverdec();
break;
case user_argsingle:
#ifdef DEBUG
DebugMessage("Scheduler: User Argument Override Single Real");
#endif
cvd->argoversingle();
break;
case user_argoverhex:
#ifdef DEBUG
DebugMessage("Scheduler: User Argument Override Hex");
#endif
cvd->argoverhex();
break;
case user_argoverchar:
#ifdef DEBUG
DebugMessage("Scheduler: User Argument Override Char");
#endif
cvd->argoverchar();
break;
case user_argoveroffsetdseg:
#ifdef DEBUG
DebugMessage("Scheduler: User Argument Override Offset Dseg");
#endif
cvd->argoveroffsetdseg();
break;
case user_argnegate:
#ifdef DEBUG
DebugMessage("Scheduler: User Argument Negate");
#endif
cvd->arg_negate();
break;
case dis_dialog:
#ifdef DEBUG
DebugMessage("Scheduler: Decoding Dialog at: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disdialog(task->addr,task->comment);
delete task->comment;
break;
case dis_stringtable:
#ifdef DEBUG
DebugMessage("Scheduler: Decoding Stringtable at: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disstringtable(task->addr,task->comment);
delete task->comment;
break;
case dis_dataword:
#ifdef DEBUG
DebugMessage("Scheduler: Making word at: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disdataword(task->addr);
break;
case dis_datadword:
#ifdef DEBUG
DebugMessage("Scheduler: Making dword at: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disdatadword(task->addr);
break;
case dis_datadsoffword:
#ifdef DEBUG
DebugMessage("Scheduler: Making dword at: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disdatadsoffword(task->addr);
break;
case dis_datastring:
#ifdef DEBUG
DebugMessage("Scheduler: Making string at: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disdatastring(task->addr);
break;
case dis_datapstring:
#ifdef DEBUG
DebugMessage("Scheduler: Making Pascal string at: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disdatapstring(task->addr);
break;
case dis_dataucstring:
#ifdef DEBUG
DebugMessage("Scheduler: Making unicode c string at: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disdataucstring(task->addr);
break;
case dis_dataupstring:
#ifdef DEBUG
DebugMessage("Scheduler: Making unicode pascal string at: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disdataupstring(task->addr);
break;
case dis_datadosstring:
#ifdef DEBUG
DebugMessage("Scheduler: Making DOS string at: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disdatadosstring(task->addr);
break;
case dis_datageneralstring:
#ifdef DEBUG
DebugMessage("Scheduler: Making general string at: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disdatageneralstring(task->addr);
break;
case dis_argoverdec:
#ifdef DEBUG
DebugMessage("Scheduler: Argument Override Decimal at: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disargoverdec(task->addr);
break;
case dis_argoverhex:
#ifdef DEBUG
DebugMessage("Scheduler: Argument Override Hex at: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disargoverhex(task->addr);
break;
case dis_argoverchar:
#ifdef DEBUG
DebugMessage("Scheduler: Argument Override Char at: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disargoverchar(task->addr);
break;
case dis_argoveroffsetdseg:
#ifdef DEBUG
DebugMessage("Scheduler: Argument Override Offset Dseg at: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disargoveroffsetdseg(task->addr);
break;
case nameloc:
#ifdef DEBUG
DebugMessage("Scheduler: Naming: %04lx:%04lx to %s",task->addr.segm,task->addr.offs,task->comment);
#endif
name->addname(task->addr,task->comment);
break;
case dis_xref:
#ifdef DEBUG
DebugMessage("Scheduler: Adding Xref at: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disxref(task->addr);
break;
case namecurloc:
#ifdef DEBUG
DebugMessage("Scheduler: Naming : %04lx:%04lx to %s",task->addr.segm,task->addr.offs,task->comment);
#endif
name->addname(task->addr,task->comment);
delete task->comment;
break;
case dis_segheader:
#ifdef DEBUG
DebugMessage("Scheduler: Segheader at : %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dta->segheader(task->addr);
break;
case dis_jumptable:
#ifdef DEBUG
DebugMessage("Scheduler: Disassembling Jumptable at : %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->disjumptable(task->addr);
break;
case dis_ordimport:
#ifdef DEBUG
DebugMessage("Scheduler: Import: %04lx:%04lx to %s",task->addr.segm,task->addr.offs,task->comment);
#endif
import->addname(task->addr,task->comment);
delete task->comment;
break;
case dis_import:
#ifdef DEBUG
DebugMessage("Scheduler: Import: %04lx:%04lx to %s",task->addr.segm,task->addr.offs,task->comment);
#endif
import->addname(task->addr,task->comment);
break;
case dis_ordexport:
#ifdef DEBUG
DebugMessage("Scheduler: Export: %04lx:%04lx to %s",task->addr.segm,task->addr.offs,task->comment);
#endif
expt->addname(task->addr,task->comment);
delete task->comment;
break;
case dis_export:
#ifdef DEBUG
DebugMessage("Scheduler: Export: %04lx:%04lx to %s",task->addr.segm,task->addr.offs,task->comment);
#endif
expt->addname(task->addr,task->comment);
break;
case seek_code:
#ifdef DEBUG
DebugMessage("Scheduler: Seek_Code : %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->codeseek(task->addr);
break;
case user_delcomment:
#ifdef DEBUG
DebugMessage("Scheduler: Delete_Comment: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->delcomment(task->addr,dsmcomment);
break;
case user_addcomment:
#ifdef DEBUG
DebugMessage("Scheduler: Add_Comment: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
dsm->discomment(task->addr,dsmcomment,(unsigned char *)task->comment);
break;
case user_delxref:
#ifdef DEBUG
DebugMessage("Scheduler: User_Del_Xref: %04lx:%04lx",task->addr.segm,task->addr.offs);
#endif
xrefs->userdel(task->addr);
break;
// case user_repeatxrefview:
// PostMessage(MainWnd,WM_REPEATXREFVIEW,(WPARAM)0,(LPARAM)0);
// break;
// case user_repeatnameview:
// PostMessage(MainWnd,WM_REPEATNAMEVIEW,(WPARAM)0,(LPARAM)0);
// break;
case user_undefineblock:
blk.undefine();
break;
case user_marktopblock:
blk.settop();
break;
case user_markbottomblock:
blk.setbottom();
break;
// case quitborg:
// threadstopped=true;
// return true;
}
// done with it, now delete it
delete task;
// }
// if (KillThread) return true;
// } while(!done);
// it is important to mark the thread as stopped if we leave here
// so that the main thread can know if it is safe to quit
// threadstopped=true;
// return procdany;
return true;
}
/************************************************************************
* sizelist *
* - this simply returns number of tasks left to process *
************************************************************************/
dword schedule::sizelist(void) {
return numlistitems();
}
/************************************************************************
* stopthread *
* - pausing and continuing the secondary thread has not been without *
* its headaches in early versions. Here I simply set threadpause and *
* wait until threadstopped is set to true. Having finally sorted out *
* most thread issues and critical sections, etc I have more or less *
* ended up with the simplest code back in here. Many problems have *
* been due to clashes of critical section code, and pausing at the *
* wrong time, or exitting and waiting for a thread to finish when it *
* was waiting for a critical section, etc. Anyway, hopefully these *
* issues are now resolved and this simple code will endure for a bit *
* - further simplified whilst commenting and analysing, Borg v2.21 *
* - Note that threadpause and threadstopped are both declared as *
* volatile variables. *
************************************************************************/
//void schedule::stopthread(void) {
// threadpause=true;
// while (!threadstopped) Sleep(0);
//}
/************************************************************************
* continuethread *
* - simply sets threadpause to false again *
* - we dont need to wait around for verification that it has continued *
************************************************************************/
//void schedule::continuethread(void) {
// threadpause=false;
//}
Detected encoding: UTF-8 | 0
|