pcsxr-1.9.92
[pcsx_rearmed.git] / macosx / EmuThread.m
CommitLineData
ef79bbde
P
1//
2// EmuThread.m
3// Pcsx
4//
5// Created by Gil Pedersen on Sun Sep 21 2003.
6// Copyright (c) 2003 __MyCompanyName__. All rights reserved.
7//
8
9#import <ExceptionHandling/NSExceptionHandler.h>
10#import <AppKit/NSApplication.h>
11#include <pthread.h>
12#include <setjmp.h>
13#import "EmuThread.h"
14#include "psxcommon.h"
15#include "plugins.h"
16#include "misc.h"
17
18EmuThread *emuThread;
19NSString *defrostPath = nil;
20static int safeEvent;
21static int paused;
22static int runbios;
23
24static pthread_cond_t eventCond;
25static pthread_mutex_t eventMutex;
26
27#define EMUEVENT_NONE 0
28#define EMUEVENT_PAUSE (1<<0)
29#define EMUEVENT_RESET (1<<1)
30#define EMUEVENT_STOP (1<<2)
31
32@implementation EmuThread
33
34- (void)EmuThreadRun:(id)anObject
35{
36 pool = [[NSAutoreleasePool alloc] init];
37
38 [[NSNotificationCenter defaultCenter] addObserver:self
39 selector:@selector(emuWindowDidClose:)
40 name:@"emuWindowDidClose" object:nil];
41
42 [[NSNotificationCenter defaultCenter] addObserver:self
43 selector:@selector(emuWindowWantPause:)
44 name:@"emuWindowWantPause" object:nil];
45
46 [[NSNotificationCenter defaultCenter] addObserver:self
47 selector:@selector(emuWindowWantResume:)
48 name:@"emuWindowWantResume" object:nil];
49
50 // we shouldn't change the priority, since we might depend on subthreads
51 //[NSThread setThreadPriority:1.0-((1.0-[NSThread threadPriority])/4.0)];
52
53 // Do processing here
54 if (OpenPlugins() == -1)
55 goto done;
56
57 setjmp(restartJmp);
58
59 EmuReset();
60
61 int res = CheckCdrom();
62 if (res == -1) {
63 ClosePlugins();
64 SysMessage(_("Could not check CD-ROM!\n"));
65 goto done;
66 }
67
68 LoadCdrom();
69
70 if (defrostPath) {
71 LoadState([defrostPath fileSystemRepresentation]);
72 [defrostPath release]; defrostPath = nil;
73 }
74
75 psxCpu->Execute();
76
77done:
78 [pool release]; pool = nil;
79 emuThread = nil;
80
81 return;
82}
83
84- (void)EmuThreadRunBios:(id)anObject
85{
86 pool = [[NSAutoreleasePool alloc] init];
87
88 [[NSNotificationCenter defaultCenter] addObserver:self
89 selector:@selector(emuWindowDidClose:)
90 name:@"emuWindowDidClose" object:nil];
91
92 [[NSNotificationCenter defaultCenter] addObserver:self
93 selector:@selector(emuWindowWantPause:)
94 name:@"emuWindowWantPause" object:nil];
95
96 [[NSNotificationCenter defaultCenter] addObserver:self
97 selector:@selector(emuWindowWantResume:)
98 name:@"emuWindowWantResume" object:nil];
99
100 // we shouldn't change the priority, since we might depend on subthreads
101 //[NSThread setThreadPriority:1.0-((1.0-[NSThread threadPriority])/4.0)];
102
103 // Do processing here
104 if (OpenPlugins() == -1)
105 goto done;
106
107 EmuReset();
108
109 psxCpu->Execute();
110
111done:
112 [pool release]; pool = nil;
113 emuThread = nil;
114
115 return;
116}
117
118- (void)dealloc
119{
120 // remove all registered observers
121 [[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:nil];
122
123 if (pool)
124 [pool release];
125
126 [super dealloc];
127}
128
129- (void)emuWindowDidClose:(NSNotification *)aNotification
130{
131 [EmuThread stop];
132}
133
134- (void)emuWindowWantPause:(NSNotification *)aNotification
135{
136 wasPaused = [EmuThread pause];
137}
138
139- (void)emuWindowWantResume:(NSNotification *)aNotification
140{
141 if (!wasPaused) {
142 [EmuThread resume];
143 }
144 wasPaused = NO;
145}
146
147/* called periodically from the emulation thread */
148- (void)handleEvents
149{
150 /* only do a trylock here, since we're not interested in blocking,
151 and we can just handle events next time round */
152 if (pthread_mutex_trylock(&eventMutex) == 0) {
153 while (safeEvent) {
154 if (safeEvent & EMUEVENT_STOP) {
155 /* signify that the emulation has stopped */
156 [emuThread autorelease];
157 emuThread = nil;
158 paused = NO;
159
160 /* better unlock the mutex before killing ourself */
161 pthread_mutex_unlock(&eventMutex);
162
163 ClosePlugins();
164 SysClose();
165
166 //[[NSThread currentThread] autorelease];
167 [NSThread exit];
168 return;
169 }
170
171 if (safeEvent & EMUEVENT_RESET) {
172#if 0
173 /* signify that the emulation has stopped */
174 [emuThread autorelease];
175 emuThread = nil;
176
177 /* better unlock the mutex before killing ourself */
178 pthread_mutex_unlock(&eventMutex);
179
180 ClosePlugins();
181
182 // start a new emulation thread
183 [EmuThread run];
184
185 //[[NSThread currentThread] autorelease];
186 [NSThread exit];
187 return;
188#else
189 safeEvent &= ~EMUEVENT_RESET;
190 pthread_mutex_unlock(&eventMutex);
191
192 longjmp(restartJmp, 0);
193#endif
194 }
195
196 if (safeEvent & EMUEVENT_PAUSE) {
197 paused = 2;
198 /* wait until we're signalled */
199 pthread_cond_wait(&eventCond, &eventMutex);
200 }
201 }
202 pthread_mutex_unlock(&eventMutex);
203 }
204}
205
206+ (void)run
207{
208 int err;
209
210 if (emuThread) {
211 [EmuThread resume];
212 return;
213 }
214
215 if (pthread_mutex_lock(&eventMutex) != 0) {
216 err = pthread_cond_init(&eventCond, NULL);
217 if (err) return;
218
219 err = pthread_mutex_init(&eventMutex, NULL);
220 if (err) return;
221
222 pthread_mutex_lock(&eventMutex);
223 }
224
225 safeEvent = EMUEVENT_NONE;
226 paused = NO;
227 runbios = NO;
228
229 if (SysInit() != 0) {
230 pthread_mutex_unlock(&eventMutex);
231 return;
232 }
233
234 emuThread = [[EmuThread alloc] init];
235
236 [NSThread detachNewThreadSelector:@selector(EmuThreadRun:)
237 toTarget:emuThread withObject:nil];
238
239 pthread_mutex_unlock(&eventMutex);
240}
241
242+ (void)runBios
243{
244 int err;
245
246 if (emuThread) {
247 [EmuThread resume];
248 return;
249 }
250
251 if (pthread_mutex_lock(&eventMutex) != 0) {
252 err = pthread_cond_init(&eventCond, NULL);
253 if (err) return;
254
255 err = pthread_mutex_init(&eventMutex, NULL);
256 if (err) return;
257
258 pthread_mutex_lock(&eventMutex);
259 }
260
261 safeEvent = EMUEVENT_NONE;
262 paused = NO;
263 runbios = YES;
264
265 if (SysInit() != 0) {
266 pthread_mutex_unlock(&eventMutex);
267 return;
268 }
269
270 emuThread = [[EmuThread alloc] init];
271
272 [NSThread detachNewThreadSelector:@selector(EmuThreadRunBios:)
273 toTarget:emuThread withObject:nil];
274
275 pthread_mutex_unlock(&eventMutex);
276}
277
278+ (void)stop
279{
280 pthread_mutex_lock(&eventMutex);
281 safeEvent = EMUEVENT_STOP;
282 pthread_mutex_unlock(&eventMutex);
283
284 // wake it if it's sleeping
285 pthread_cond_broadcast(&eventCond);
286}
287
288+ (BOOL)pause
289{
290 if (paused || ![EmuThread active])
291 return YES;
292
293 pthread_mutex_lock(&eventMutex);
294 safeEvent |= EMUEVENT_PAUSE;
295 paused = 1;
296 pthread_mutex_unlock(&eventMutex);
297
298 pthread_cond_broadcast(&eventCond);
299
300 return NO;
301}
302
303+ (BOOL)pauseSafe
304{
305 if ((paused == 2) || ![EmuThread active])
306 return YES;
307
308 [EmuThread pause];
309 while ([EmuThread isPaused] != 2) [NSThread sleepUntilDate:[[NSDate date] addTimeInterval:0.05]];
310
311 return NO;
312}
313
314+ (void)resume
315{
316 if (!paused || ![EmuThread active])
317 return;
318
319 pthread_mutex_lock(&eventMutex);
320
321 safeEvent &= ~EMUEVENT_PAUSE;
322 paused = NO;
323 pthread_mutex_unlock(&eventMutex);
324
325 pthread_cond_broadcast(&eventCond);
326}
327
328+ (void)reset
329{
330 pthread_mutex_lock(&eventMutex);
331 safeEvent = EMUEVENT_RESET;
332 pthread_mutex_unlock(&eventMutex);
333
334 pthread_cond_broadcast(&eventCond);
335}
336
337// must only be called from within the emulation thread!!!
338+ (void)resetNow
339{
340 /* signify that the emulation has stopped */
341 [emuThread autorelease];
342 emuThread = nil;
343
344 ClosePlugins();
345
346 // start a new emulation thread
347 [EmuThread run];
348
349 //[[NSThread currentThread] autorelease];
350 [NSThread exit];
351 return;
352}
353
354+ (BOOL)isPaused
355{
356 return paused;
357}
358
359+ (BOOL)isRunBios
360{
361 return runbios;
362}
363
364+ (BOOL)active
365{
366 return emuThread ? YES : NO;
367}
368
369+ (void)freezeAt:(NSString *)path which:(int)num
370{
371 BOOL emuWasPaused = [EmuThread pauseSafe];
372 char Text[256];
373
374 GPU_freeze(2, (GPUFreeze_t *)&num);
375 int ret = SaveState([path fileSystemRepresentation]);
376 if (ret == 0) sprintf (Text, _("*PCSX*: Saved State %d"), num+1);
377 else sprintf (Text, _("*PCSX*: Error Saving State %d"), num+1);
378 GPU_displayText(Text);
379
380 if (!emuWasPaused) {
381 [EmuThread resume];
382 }
383}
384
385+ (BOOL)defrostAt:(NSString *)path
386{
387 const char *cPath = [path fileSystemRepresentation];
388 if (CheckState(cPath) != 0)
389 return NO;
390
391 defrostPath = [path retain];
392 [EmuThread reset];
393
394 GPU_displayText(_("*PCSX*: Loaded State"));
395 return YES;
396}
397
398@end