-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathleakwatch.c
358 lines (295 loc) · 8.77 KB
/
leakwatch.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
/**************************************************
*** Project Title: Command Post (KFLASH) ***
*** Author: Greg Dietsche ***
*** Date: 07/23/2002 ***
*** Description: An application designed for ***
*** use with the TI-89 and TI-92 Plus Graphing ***
*** calculators during the testing and ***
*** debugging phases of FLASH APPS and RAM ***
*** programs ***
***************************************************/
// $Id: leakwatch.c 4 2004-08-05 19:06:59Z dietsche $
#include <tiams.h>
#include "KFLASH.h"
#include "KFLASHr1.H"
#include "leakwatch.h"
#include "undoc.h"
static void LeakWatch_Event_Handler(pFrame self, PEvent e);
static BOOL LeakWatchAppCanDelete(AppID self);
static BOOL LeakWatchAppCanMove(AppID self);
static BOOL AppHasLeakWatch(AppID app);
static void InstallLeakWatch(AppID app);
static void UninstallLeakWatch(AppID app);
static void LeakWatchAll(void);
static VAR_TABLE_INFO *VarTableSize(void);
static void LeakWatchStart(LEAK_INFO *w);
FRAME(LeakWatchFrame, OO_SYSTEM_FRAME, 0, OO_APP_PROCESS_EVENT, 1)
ATTR(OO_APP_PROCESS_EVENT, &LeakWatch_Event_Handler) //0x0004
// ATTR(OO_APP_CAN_DELETE, &LeakWatchAppCanDelete) //0x000C
// ATTR(OO_APP_CAN_MOVE, &LeakWatchAppCanMove) //0x000D
ENDFRAME
void LeakWatchDialog(void)
{
Access_AMS_Global_Variables;
LEAK_DAT *d=&global.leak_dat;
char *pupText;
char buff[250];
d->optList[1]=1; //force currently selected app to be index #1
TRY
switch(Dialog(&dlgLeakWatch, -1, -1, NULL, d->optList))
{
case KB_ENTER:
if(strlen(pupText=PopupText(d->pupApps, d->optList[1])))
switch(d->optList[0])
{
case LEAK_INSTALL:
if(!strcmp(XR_stringPtr(XR_AllApps), pupText))
LeakWatchAll();
else
InstallLeakWatch(OO_AppNameToACB((UCHAR *)pupText, TRUE));
sprintf(buff, XR_stringPtr(XR_LeakWatchInstall), pupText);
DlgNotice(XR_stringPtr(XR_LongAppName), buff);
break;
case LEAK_UNINSTALL:
if(!strcmp(XR_stringPtr(XR_AllApps), pupText))
LeakWatchNone();
else
UninstallLeakWatch(OO_AppNameToACB((UCHAR *)pupText, TRUE));
sprintf(buff, XR_stringPtr(XR_LeakWatchRemove), pupText);
DlgNotice(XR_stringPtr(XR_LongAppName), buff);
break;
};
break;
case DB_MEMFULL: //handle low memory error
EV_errorCode=ER_MEMORY;
break;
}
ONERR
EV_errorCode=errCode;
ENDTRY
HeapFreeIndir(&d->pupApps);
}
HANDLE pupLeakWatchApps(WORD index)
{
Access_AMS_Global_Variables;
LEAK_DAT *d=&global.leak_dat;
HANDLE *h=&d->pupApps;
AppID appid;
HeapFreeIndir(h);
*h=PopupNew(NULL, 0);
for(appid=OO_firstACB; appid; appid=OO_NextACB(appid))
{
switch(d->optList[0])
{
case LEAK_INSTALL:
if(IsLeakWatchable(appid))
PopupAddText(*h, -1, (char *)GetAppName(appid), 0);
break;
case LEAK_UNINSTALL:
if(AppHasLeakWatch(appid))
PopupAddText(*h, -1, (char *)GetAppName(appid), 0);
break;
};
}
if(strlen(PopupText(*h, 2)))//if there is more than 1 item in the dynamic popup
PopupAddText(*h, -1, XR_stringPtr(XR_AllApps), 0);//add the All Apps option
return *h;
}
static void LeakWatchAll(void)
{
Access_AMS_Global_Variables;
AppID appid;
for(appid=OO_firstACB; appid; appid=OO_NextACB(appid))
{
if(IsLeakWatchable(appid))
InstallLeakWatch(appid);
}
}
void LeakWatchNone(void)
{
Access_AMS_Global_Variables;
AppID appid;
for(appid=OO_firstACB; appid; appid=OO_NextACB(appid))
{
if(AppHasLeakWatch(appid))
UninstallLeakWatch(appid);
}
}
//this routine may throw a low memory error
static void InstallLeakWatch(AppID app)
{
LEAK_DAT *d=&global.leak_dat;
LEAK_NODE *node=&d->head;
LEAK_NODE *previous;
while(node->next)node=HeapDeref(node->next); //find the last node
previous=node;
previous->next=HeapAllocThrow(sizeof(LEAK_NODE));
node=HeapDeref(previous->next);
node->app=app;
node->next=H_NULL;
if(!OO_InstallAppHook(app, (pFrame)&LeakWatchFrame, &node->frame))
{
HeapFreeIndir(&previous->next);
ER_throw(ER_MEMORY);
}
}
static void UninstallLeakWatch(AppID app)
{
LEAK_DAT *d=&global.leak_dat;
LEAK_NODE *node=&d->head;
LEAK_NODE *previous=node;
HANDLE not_the_whales;
do {
if(app==node->app)break;
previous=node;
}while(node=node->next?HeapDeref(node->next):NULL);
OO_UninstallAppHook(app, node->frame); //unhook
not_the_whales=previous->next;
previous->next=node->next; //adjust linked list
HeapFree(not_the_whales); //free this node
}
//returns true if a app has a leak watch frame installed
static BOOL AppHasLeakWatch(AppID app)
{
LEAK_DAT *d=&global.leak_dat;
LEAK_NODE *node=&d->head;
while(node=node->next?HeapDeref(node->next):NULL) {
if(app==node->app)
return TRUE;
}
return FALSE;
}
BOOL LeakWatchAppsNotActive(void)
{
Access_AMS_Global_Variables;
LEAK_DAT *d=&global.leak_dat;
LEAK_NODE *node=&d->head;
while(node=node->next?HeapDeref(node->next):NULL) {
if(EV_runningApp==node->app) //use of Running App is important! i.e. background events, etc...
return FALSE;
}
return TRUE;
}
//callback routine for dlgLeakWatch
DWORD cbLeakWatch(WORD DlgId, DWORD dValue)
{
if(DlgId==0) return DB_REDRAW_AND_CONTINUE;
return TRUE;
}
void export_LeakWatchBegin(void)
{
LEAK_DAT *d=&global.leak_dat;
LeakWatchStart(&d->external);
}
DWORD export_LeakWatchEnd(char *title)
{
LEAK_DAT *d=&global.leak_dat;
return LeakWatchEnd(title, &d->external);
}
static void LeakWatchStart(LEAK_INFO *w)
{
w->ram=HeapAvail();
w->vtbl.mem_used=VarTableSize()->mem_used;
w->vtbl.handles_used=VarTableSize()->handles_used;
w->freehandles=FreeHandles();
}
DWORD LeakWatchEnd(char *title, LEAK_INFO *w)
{
DWORD deltamem=HeapAvail()-w->ram;
DWORD deltavar=VarTableSize()->mem_used-w->vtbl.mem_used;
DWORD deltavarhandle=VarTableSize()->handles_used-w->vtbl.handles_used;
short deltahandles=FreeHandles()-w->freehandles;
char buff[500];
deltahandles+=deltavarhandle; //adjust deltahandles to negate any vartable size change
if(deltamem || deltahandles || deltavar)
{
sprintf(buff, OO_AbsoluteGet(OO_FIRST_APP_STRING + XR_LeakWatchStr),
deltamem,
deltavar,
deltamem+deltavar, //adjust to negate any vartable size
deltahandles);
DlgNotice(title, buff);
}
return deltamem;
}
static void LeakWatch_Event_Handler(pFrame self, PEvent e)
{//when passing events on, it is very important to check OO_SuperFrame, or
//seemingly random errors can occur
Access_AMS_Global_Variables;
LEAK_DAT *d=&global.leak_dat;
pFrame super = OO_SuperFrame;
char *appname=OO_GetAttr(self, OO_APP_NAME);
char buff[500];
switch (e->command)
{
case CM_START:
LeakWatchStart(&d->internal);
if(super) AppProcessEvent(super, e);
break;
case CM_QUIT:
if(super) AppProcessEvent(super, e);
LeakWatchEnd((char *)appname, &d->internal);
break;
case CM_PACK:
sprintf(buff, OO_AbsoluteGet(OO_FIRST_APP_STRING + XR_LeakPackInfo) , appname);
DlgNotice(appname, buff);
case CM_UNINSTALL:
UninstallLeakWatch(((ACB*)HeapDeref(OO_AppNameToACB((UCHAR*)appname, TRUE)))->myID);
if(super) AppProcessEvent(super, e);
break;
default:
if(super) AppProcessEvent(super, e);
};
}
//calculate the size of the variables in the var-link
//this is probabbly best treated as an estimate...
static VAR_TABLE_INFO *VarTableSize(void)
{
register SYM_ENTRY *sym;
static VAR_TABLE_INFO vtbl;
vtbl.mem_used=0;
vtbl.handles_used=0;
FolderOp(NULL, FL_ALL | FL_LOCK);
sym=SymFindFirst(NULL, FO_RECURSE);
while(sym)
{
if(!(sym->Flags & SF_EXTMEM)) //don't count archived variables
{
ULONG handle=(ULONG)HeapDeref(sym->hVal);
if(handle!=0 && handle!=0xffffffff) //make sure the handle exists, or HeapSize will crash
{//some flash apps make variables without giving them handles.... and then context switch to
//another app... like *cough* CalcTools *cough*
vtbl.mem_used+=HeapSize(sym->hVal)+2;
vtbl.handles_used++;
}
}
sym=SymFindNext();
}
FolderOp(NULL, FL_ALL | FL_UNLOCK);
return &vtbl;
}
/*
typedef struct{
DWORD mem_used; //size used by homescreen vars
DWORD handles_used; //number of handles used by home screen pairs
}HOME_INFO;
static HOME_INFO *HomeInfo(void)
{
register short counter=0;
HANDLE h;
static HOME_INFO hinf;
hinf.mem_used=0;
hinf.handles_used=0;
while(h=HS_getEntry(counter++))
{
hinf.mem_used+=HeapSize(h);
if(h=HS_getAns(counter))
{
hinf.mem_used+=HeapSize(h);
hinf.handles_used++;
}
hinf.handles_used++;
}
return &hinf;
}
*/