Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » allegro_exit in a timer!!!

Credits go to Bob, gillius, Kris Allen, Peter Hull, ReyBrujo, spellcaster, and Yves Rizoud for helping out!
This thread is locked; no one can reply to it. rss feed Print
 1   2 
allegro_exit in a timer!!!
Iain Price
Member #4,994
September 2004

Right heres a good one for you...I'm new to allegro but not programming. Please be gentle.... :)

I am writing an emulator, so I do not have control over the main loop of the program. I have a timer that checks for ESC being pressed, and calls unload_shite and then allegro_exit. If I end the emu with the ESC key it does not exit cleanly - sometimes execption errors, sometimes a hang. I think I am cleaning variables and memory OK, I think my problems are from trying to exit from within a timer... any advice????

void unload_shite(void)
{
remove_int(timers1ms);
remove_int(emu_draw_reel);
remove_int(emu_lamp_updateflash);
remove_int(emu_check_hoppers);
if (background)
destroy_bitmap(background);
if (emu_fruits_data)
unload_datafile(emu_fruits_data);
set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
remove_int(timers10ms); //called from here in a timer
clear_keybuf();
}

Help. :'(

spellcaster
Member #1,493
September 2001
avatar

Do you have a mouse cursor visible? In this case you need to hide the mouse.
If you end the program anyway, you can also get rid of the allegro_exit(), which is IMHO not save to call from a timer.

--
There are no stupid questions, but there are a lot of inquisitive idiots.

ReyBrujo
Moderator
January 2001
avatar

First, use [CODE] and [/CODE] to surround code (in lowercase, otherwise it won't work).

Now, I hope the timer isn't accessing the key[] array. In fact, why you would use such timer? Can't you put it inside your main cycle? Also, you call unload_shite from inside the timer? Bad idea. You would update a variable to 1, and later in the cycle, check if the variable is 1 or 0. If it is 0, you continue with the emulation. If it is 1, you call unload_shite.

Why it hangs? Most probably because you are calling that function from inside a timer. When it enters the timer, it begins unloading everything. Since all that is very slow, it is likely the timer will tick again before you finish unloading, so it will go back to this function and try again to unload what was already unloaded. Also, the heap can be corromped if the same timer happens twice or more.

--
RB
光子「あたしただ…奪う側に回ろうと思っただけよ」
Mitsuko's last words, Battle Royale

Iain Price
Member #4,994
September 2004

I have no mouse. I also have no control over the main loop. As it is an emulator, the main loop depends on the code it is emulating. I can however run tasks in timers in the background, this is where I do the checking for escape, and if so I unload data and call allegro_exit.

If I could do it in the main loop, I would, but I can't.

What would happen if I was to remove the timer function that called the kill function, would it complete or would it stop in mid call?

Bob
Free Market Evangelist
September 2000
avatar

Quote:

As it is an emulator, the main loop depends on the code it is emulating.

That sounds like horribly broken design...

You can't do much in a timer. Plan for that.

--
- Bob
[ -- All my signature links are 404 -- ]

Iain Price
Member #4,994
September 2004

I think I need to explain more about the software. When developing fruit machines you need a prototype machine to test software on. I am writing a set of libraries that compile in with the software an emulate the machine on a PC so no prototype is needed. This means that all I can write is a library, therefore I cannot control the main loop as that is the fruit machines software. I can however setup timers etc for updating the reel graphics etc. Unfortunately any code I want in the machine has to be done in timers - horrid but hey thats the way it goes.

I think my prblem may be that the function is taking too long for a 10ms timer. I am still wondering what would happen if I removed the 10ms timer from the list from within the 10ms timer, would it complete and then not get called again or would it stop functioning?

Peter Hull
Member #1,136
March 2001

Are you saying that you have the source code* for a fruit machine, and you want to write an emulator so that it will run on a PC for testing?

Allegro timers aren't right for this because you're not supposed to run anything that takes a significant amount of time in them.

How does the fruit machine software update the state of the fruit machine? By functions in a standard library, or setting global variables, or what? If it is the first, you might be able to hijack some of these functions to do Allegro stuff.

In other words, if you have something like

while (1) {
 flash_lights();
 wait_for_coin();
}

you could put your key[KEY_ESC] test in flash_lights(), see what I mean?

void flash_lights(void) {
 if (key[KEY_ESC]) {
   la la la
 }
 really_flash_lights();
}

I have no idea how a fruit machine works (do they program them in C?) as you might have guessed, so this is all speculation...

Pete

*i.e not just the compiled object file.

Iain Price
Member #4,994
September 2004

The idea is that anyone can comile these libraries into their machine instead of the hardware libraries. All they have to do is use a function called:

void Game(void)
{
}

as their entry point and they write their game from there on - this is the same for if they were using the hardware. My library sets up the screen, with fruit machine image and kicks off timers that are available to the main machine i.e. background timers to update reel graphics every 10ms if the reel is spinning or to flash bulbs every 250ms - the prgrammer uses functions like flash_lamp(nnn) and I set that lamp to flash and update it every 250ms. These emulate the hardware... its not going too badly but gcc and allegro cannot cope with mask shifts e.g if (hex_mask & (1<<0x01))

and it cannot seem to cope with a shutdown from a timer event...

but hey, these little problems are there to add spice to life....

Peter Hull
Member #1,136
March 2001

OK, but as I mentioned, you "shouldn't" be updating graphics and stuff in timers. You might get away with it but the program will, I think, be inherently unstable and liable to unpredictable crashes.

When a fruit machine is waiting for something to happen (reels to stop or player to press something), what's it doing? Is it repeatedly calling a function? If so, you can put the graphics update stuff in there.

Otherwise, you need to do multithreading, where Game() runs in its own thread.

Is this for business or pleasure by the way?

Pete

ps. I can't see anything wrong with your mask shift - what happens?

Iain Price
Member #4,994
September 2004

The "main" function for allegro sets up the screen timers etc as I mentioned but the it calls "Game" and after that it finishes. The contents of the Game function depends on what the fruit machine programmer decides to put in there, my emu has no control.

The "Game" procedure cannot contain any calls to allegro code as it would then not work when the hardware libraries were compiled back in instead.

Initially this is to help me with my work, so that I don't need a prototype for each new project, but obviously if it ends up being stable, useful and proffessional I may release it to the rest of the fruit machine industry.

(the shift mask compiles but when executed the program quits)

gillius
Member #119
April 2000

timers are threaded, so you need to use actual threading code if you want to do this. I'm not sure how the main thread interacts with Allegro, but if there is a well-defined interface that you are trying to pick up, then you can do it with a single timer or a separate thread, but you need to be careful as Allegro is NOT a thread-safe library.

Gillius
Gillius's Programming -- https://gillius.org/

Peter Hull
Member #1,136
March 2001

As I understand it, you have a main game file which you link with a library. This library is either the fruit machine hardware control stuff or your emulator. Is this right?

As long as your game calls any function in the libary at frequent intervals, you can sneak in calls to another function, which updates the graphics. Allegro is never called directly from Game().

This update function looks at the current time, and the state of the machine, then draws the graphics accordingly. Something like this

if (lamp1_on && ((tick_count % lamp1_flash_time)<(lamp1_flash_time/2)) {
 draw_lamp1_on();
}
else {
 draw_lamp1_off();
}

tick_count is updated in a timer.

Pete

Iain Price
Member #4,994
September 2004

Basically thats how it works.

The idea is that allegro is instead of the hardware, but a hidden timer to check for an allegro keypress to end the program doesnt seem possible without hangs or exception errors.. :(

gillius
Member #119
April 2000

Why can't you check for key presses from the main thread when you are doing the normal ALlegro calls?

Gillius
Gillius's Programming -- https://gillius.org/

Iain Price
Member #4,994
September 2004

By main thread I assume you mean the main program loop... as I said before that section of code is used by the fruit machine and needs to be able to be allegro OR hardware so I can't use calls specific to either....

Yves Rizoud
Member #909
January 2001
avatar

Quote:

I think my problems are from trying to exit from within a timer

If this is the problem, you could maybe get away by using setjmp() / longjmp() ?

Peter Hull
Member #1,136
March 2001

Gillius,

As I understand it, he's got:
main() sets up Allegro, starts some timers and then calls Game()
Game() contains the main logic and manipulates the state of the machine in some way.
The timer functions read the machine state and call Allegro graphics and sound functions.

i.e. Game is in the main thread and Allegro calls are made from the timer thread.

Iain,

Can I ask again: when the fruit machine is doing 'nothing' (waiting for something to happen) is it calling any function repeatedly in a loop or not? It would help a lot if you could post a simple example of a Game() function.

Cheers

Pete

Iain Price
Member #4,994
September 2004

I'm nor sure if this will mean much but here is an example:

1void Game(void)
2{
3 device=&SerialDevice; /* Select communications device */
4 
5 do
6 {
7 cycstart();
8
9 waitforcredit();
10 
11 if(!repeat_active)
12 waitforstart();
13 
14 if(use_ram.credit>=cost_of_play)
15 {
16 add_to_comp();
17
18 if(!repeat_active)
19 {
20 if(current_cheat)
21 cheat_reels();
22 else
23 game_reels();
24
25 reels_spin_outcome();
26 trail_spin_outcome();
27 nudge_spin_outcome();
28 check_feature();
29 }
30 }
31 send_datapak_end_of_game();
32 cycend();
33 }
34 while(1);
35}

When the machine is sat waiting for things to happen e.g. coin in, it is in a loop controlled but the main game code. I cannot add allegro code in the main loop. There is nothing that is called again and again - well not guaranteed anyway because it depends on the person who has written the code....

Peter Hull
Member #1,136
March 2001

Ok, take waitforcredit() as an example; is that function in the standard library or does the programmer write that for each different game?

Pete

Iain Price
Member #4,994
September 2004

All of those listed are custom procedures.

Only the very low-level- input on, input off, step_motor commands are in the library. There really is no other way other than on a timer. I know its ugly and nasty but I just need to find a secure way of doing it.....

:'(

gillius
Member #119
April 2000

then dont' use a timer. Use a separate thread to communicate with allegro. Assuming you can get synchronized access to the machine's state you are fine. You must develop some sort of solution to ensure synchronization with the thread running the Game function, so that you can access the machine's state from the other thread. If you restrict all usage of Allegro to that thread and timers started from that thread you'll be fine. The other way of phrasing it is that you use a main thread to do Allegro stuff and timers, just like any other Allegro game, except that you fork off a new thread to do the game logic.

Gillius
Gillius's Programming -- https://gillius.org/

Kris Allen
Member #4,639
May 2004
avatar

Quote:

I have no idea how a fruit machine works (do they program them in C?)

don't be silly! everyone knows there's a bunch of really tiny little men in there that make everything work

- Kris

Iain Price
Member #4,994
September 2004

Not sure how to make a parallel thread....

any examples out there?

gillius
Member #119
April 2000

CreateThreadEx. pthread_create. look them up, and I'm sure there will be many examples.

You can look at my GNE library [url http://www.sf.net/projects/gnelib], specifically the class Thread to see how to create a thread. You might be able to use the class itself directly in your code with only trivial modification. If you do so, you (Iain Price) have my permission to take only the class Thread and modify and redistribute the class for any purpose you wish, ignoring the statement that the code is covered under the LGPL license. If you wish to use other code/classes from GNE, you must follow the license as usual (as stated in the code).

EDIT: it seems I use a lot of other classes in that code, so maybe you wouldn't be able to use it directly, but you can still use it to see how you can initialize and start a thread in Win32 and POSIX environments.

Gillius
Gillius's Programming -- https://gillius.org/

Peter Hull
Member #1,136
March 2001

Quote:

There really is no other way other than on a timer.

There's always A Way ;)

The thread way should work fine, as Gillius says. My only query would be how to terminate the Game thread cleanly. Is it OK just to call exit() letting the OS kill any threads and free any resources?

The single thread approach would require you to write an Allegro update function and call it from within each of the low-level library calls. It's not as neat an implementation, but it will save you the hassle of synchronisation which can be a nuisance and a source of subtle errors.

Are you using Windows by the way?

Pete

 1   2 


Go to: