Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » LOCK_FUNCTION / LOCK_VARIABLE

Credits go to Derezo and ReyBrujo for helping out!
This thread is locked; no one can reply to it. rss feed Print
LOCK_FUNCTION / LOCK_VARIABLE
spellcaster
Member #1,493
September 2001
avatar

Is it save to call these macros several times?

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

Derezo
Member #1,666
April 2001
avatar

All it does is this.

Quote:

This function may be called more than once for a given page; the DPMI host maintains a lock count for each page.

Note that it uses different methods on different platforms.. so I'm not sure if it does exactly that on all platforms.

I'd recommend keeping track of whether or not you've done it anyways, though.

"He who controls the stuffing controls the Universe"

Sirocco
Member #88
April 2000
avatar

I don't see why not. I'm assuming that if the memory is already locked, at worst it'll return a failure value. Generally speaking, I know everything I'll need to lock at run time, so I've never actually ran into this particular situation.

-->
Graphic file formats used to fascinate me, but now I find them rather satanic.

ReyBrujo
Moderator
January 2001
avatar

Wondering, why would that happen? You lock variables only once. I don't believe it will return a failure, because technically speaking, you asked to lock the memory, and the memory was already locked.

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

spellcaster
Member #1,493
September 2001
avatar

The question is: Do I need to keep track of the fact that I've locked the var, or is it ok to lock it several times?

It's not a real problem, it would be pretty easy to avoid it, but it would require some work. If there's some sort of UNLOCK_XXX macro, it would be ok as well.

I've several states, the init rule of the state does all the init stuff (suprise, heh), the done rule clears up. I lock the var in the init rule, but since I can't unlock it in the done rule it's possible that the same var gets locked several times.

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

Derezo
Member #1,666
April 2001
avatar

Quote:

Do I need to keep track of the fact that I've locked the var, or is it ok to lock it several times?

You don't need to keep track, and it is ok to lock it several times.

There shouldn't be a reason you lock it several times, though. Initialization on locked variables should only occur once.

It's like setting a graphics mode. You can do it more than once, but that'd just be silly.

That's just coding practice, though..

[edit: btw, you can unlock memory, but allegro doesn't have a macro to do it.]

"He who controls the stuffing controls the Universe"

ReyBrujo
Moderator
January 2001
avatar

I believe if you lock something several times, if it throws errors, you would not matter them. As long as it does not throw an exception, you should be able to recover from the error.

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

Derezo
Member #1,666
April 2001
avatar

My bad, allegro DOES have unlock macro's.

#define LOCK_DATA(d, s)             _go32_dpmi_lock_data(d, s)
#define LOCK_CODE(c, s)             _go32_dpmi_lock_code(c, s)
#define UNLOCK_DATA(d,s)            _unlock_dpmi_data(d, s)
#define LOCK_VARIABLE(x)            LOCK_DATA((void *)&x, sizeof(x))
#define LOCK_FUNCTION(x)            LOCK_CODE((void *)FP_OFF(x), (long)FP_OFF(x##_end) - (long)FP_OFF(x))

UNLOCK_DATA((void*)&var, sizeof(var)) is what you'd want for that, I bet..

By the looks of it that's only for variables..

"He who controls the stuffing controls the Universe"

spellcaster
Member #1,493
September 2001
avatar

Quote:

There shouldn't be a reason you lock it several times, though. Initialization on locked variables should only occur once.

Well, not really. View it like locking the screen, since this is a pretty good analogy: You lock the screen, do your stuff and unlock it.

The problem is, that I can't unlock the variable. There's no symetric function/macro for the LOCK_XXX macros.

Quote:

It's like setting a graphics mode. You can do it more than once, but that'd just be silly.

Unless you want to switch to a different gfx mode or color depth, eh?

Quote:

That's just coding practice, though..

Well, maybe you can tell me how you'd handle this? I'm always willing to learn :)

Right now the only way I can think of would be to store the fact that I've locked the variable in a state variable.

init-rule: 
    if (varLocked is not true) {
        lock(var);
        varLocked = true;
    }

What'd I'd prefer would be:

init-rule: lock(var)
done-rule: unlock(var)

That would keep everything symetric.

EDIT: You're too fast :)

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

Derezo
Member #1,666
April 2001
avatar

Quote:

Well, maybe you can tell me how you'd handle this? I'm always willing to learn :)

1#include <allegro.h>
2#include "gui.h"
3#include "platformer.h"
4#include "timers.h"
5#include "graphics.h"
6#include "tiles.h"
7 
8int fpsCounter;
9int fps;
10int ms, sec, min, hr;
11int logicUpdates;
12 
13void LogicTimer(void)
14 {
15 logicUpdates++;
16 }
17END_OF_FUNCTION(LogicTimer);
18 
19void ClockTimer(void)
20 {
21 ms++;
22 if(ms >= 100)
23 {
24 ms = 0;
25 sec++;
26 if(sec >= 60)
27 {
28 sec = 0;
29 min++;
30 if(min >= 60)
31 {
32 hr++;
33 }
34 }
35 }
36 }
37END_OF_FUNCTION(ClockTimer);
38 
39void FPSTimer(void)
40 {
41 fps = fpsCounter;
42 fpsCounter = 0;
43 }
44END_OF_FUNCTION(FPSTimer);
45 
46int InitTimers()
47 {
48 LOCK_FUNCTION(LogicTimer);
49 LOCK_FUNCTION(ClockTimer);
50 LOCK_VARIABLE(ms);
51 LOCK_VARIABLE(sec);
52 LOCK_VARIABLE(min);
53 LOCK_VARIABLE(hr);
54 LOCK_VARIABLE(logicUpdates);
55 LOCK_VARIABLE(fps);
56 LOCK_VARIABLE(fpsCounter);
57 
58 install_int(LogicTimer,30);
59 install_int(ClockTimer,10);
60 install_int(FPSTimer,1000);
61 
62 return 1;
63 }

I call InitTimers(), done. Never touch any of that again.

Those variables never get touched ever again. No unlocking, no locking, just reading. With the case of logicUpdate, I subtract one each time I make a logic update. With fpsCounter, I add one each time I draw a frame.

Note: Variables need to be initialized to 0.

Quote:

Unless you want to switch to a different gfx mode or color depth, eh?

Where locking variables is concerned, you can't switch the way you do it. So I think the analogy still stands, but I mean setting it to the same thing. Changing it from 640x480x16 to 640x480x16 :P

"He who controls the stuffing controls the Universe"

Richard Phipps
Member #1,632
November 2001
avatar

I do it the same as Derezo. Never had any problems. :)

spellcaster
Member #1,493
September 2001
avatar

Quote:

I call InitTimers(), done. Never touch any of that again.

Well, that's great. Now, please tell me how you do it with the state machine I've described? :)

I choose the easy way and added a watcher for the locked state.
Just to get some "OH NOW! EVIL MACROS!" shouts, here're my new timer macros:

1#define TIMER_DECL(VAR) \
2 volatile int VAR = 0; \
3 int VAR##isLocked = 0; \
4 static void VAR##Updater(){ \
5 VAR++; \
6 } END_OF_STATIC_FUNCTION(VAR##Updater)
7 
8#define TIMER_SET(VAR, FPS) \
9 if (!VAR##isLocked) { \
10 LOCK_FUNCTION(VAR##Updater); \
11 LOCK_VARIABLE(VAR); \
12 VAR##isLocked = 1; \
13 } \
14 install_int_ex(VAR##Updater, BPS_TO_TIMER(FPS))

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

Derezo
Member #1,666
April 2001
avatar

Quote:

Now, please tell me how you do it with the state machine I've described?

I don't understand the difference. You're using the same variables each time, so it should be no different.
Lock them once in a single swoop (such as after calling install_timer), and never touch them again. Locking variables is not something you should even have to consider doing more than once during a program's execution.

Set it and forget it!™

Evil macro's work, too, though ;D

"He who controls the stuffing controls the Universe"

Oscar Giner
Member #2,207
April 2002
avatar

Will you declare a lot of variables to be timer incremented? Because allegro has a low limit on number on timer ints. I think it's a total of 16 (and some subsystems already take some of those).

In this case, I'd only install 1 high resolution timer and update all variables in this timer.

spellcaster
Member #1,493
September 2001
avatar

Quote:

I don't understand the difference. You're using the same variables each time, so it should be no different.
Lock them once in a single swoop (such as after calling install_timer), and never touch them again. Locking variables is not something you should even have to consider doing more than once during a program's execution.

The difference is that each module is like your program.
If you call your program trice in a row, you rely on the fact that the OS clears the system every time.
If you don't have that luxury, you need to take care of it yourself.

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

Kitty Cat
Member #2,815
October 2002
avatar

The LOCK_* macros are only applicable in DOS. And I think the fact that Allegro tries to unlock data before freeing it (in the case of pointers) means that the data should be unlocked. However, I don't think this applies to variables since Allegro never states anyewhere that you should unlock variables before closing the program.

So I think you only need to worry about unlocking if you're locking a piece of malloc'd memory that will be free'd.

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Gideon Weems
Member #3,925
October 2003

What is the ## notation in spellcaster's macros? It seems to concatenate VAR as an identifier. If so, I like!

Thomas Fjellstrom
Member #476
June 2000
avatar

Quote:

The difference is that each module is like your program.

1program_init {
2 foreach module {
3 module->init();
4 }
5}
6 
7program_run {
8 // selected_module->start();
9 selected_module->run();
10 // selected_module->end();
11}
12 
13program_exit {
14 foreach module {
15 module->exit();
16 }
17}

Something like that anyhow.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

spellcaster
Member #1,493
September 2001
avatar

Quote:

What is the ## notation in spellcaster's macros? It seems to concatenate VAR as an identifier. If so, I like!

It's the concat operator. There's also a string operator #

Quote:

program_init {
foreach module {
module->init();
}
}

program_run {
// selected_module->start();
selected_module->run();
// selected_module->end();
}

program_exit {
foreach module {
module->exit();
}
}

Yep. Now, imagine that these modules are dynamic.

This code shoulnd't leak resources:

while (1) {
    Object foo = new Object();
    delete foo;
}

In the same way, these calls shouldn't leak resources

while(1) {
    state_init(state);
    state_done(state);
}

Agreed?

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

Thomas Fjellstrom
Member #476
June 2000
avatar

Uhhh...

while(1) {
    state_init(state);
    state_done(state);
}

add a few states. Like "start" and "end" leave "init" and "done" for the stuff that CAN'T be done over and over. Which is what I was "trying" to say with the last bit of code.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

spellcaster
Member #1,493
September 2001
avatar

Well, init() is the constructor. done() the destructor :)
What you're doing is to design-by-contract. You force the user (or yourself) to call those routines only once.
If you have start and init what you do is to force the player to keep the state in mind. he has to make sure that start or init (just from the name, I can't even tell what method should be called only once) is called just once.
So, all you do is delegating the responsibilty to the user. I consider this to be rude.

You should be able to create and free a state without wasting resources. I think we agree here?
And if I have to waste resources, it should be the responsibility of the state to ensure that the least amount possible is wasted.

With your approach, you either have to know all states at compile time (so no data driven aopproach is possible) or the user has to keep book whether he has called the "once in a life time method" or the state has to have a "isStartNeeded()/isInitNeeded()" the user can call... or it simply does the check itself - which is my current solution :)

What you're trying to do will result in exactly the same thing as I do. But you force the user to do the work, my code does it automatically. So I'm not sure I see your point.

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

Thomas Fjellstrom
Member #476
June 2000
avatar

What wasted resources? Its Locking a variable ::)

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

spellcaster
Member #1,493
September 2001
avatar

Well, that's the point. Nobody was really quite sure whether it was save to call it sveral times or not, and what happens if it's called several times.
But there should be a symetric call to unlock it.
With your point of view, there's either no need at all to worry (then most of your posts in this thread don't make much sense any more ("why having a once in a programs-lifetime-method if it doesn't matter if it's called twice)).
With my point of view, stuff that is locked should be freed, since I don't know what the lock call does. It might differ from platform to platform, etc.

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

Thomas Fjellstrom
Member #476
June 2000
avatar

Except that its a legacy hold over from the DOS code, and really isn't required in the other platforms :o

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

spellcaster
Member #1,493
September 2001
avatar

Well, it's not yet depricated. If it's not required at all, then most of this discussion was pretty pointless :)

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

Go to: