Page 1 of 2

[solved] Using IDOS->NotifyVar() in library?

Posted: Fri Aug 09, 2013 9:37 pm
by gazelle
I'm trying to use IDOS->NotifyVar inside a library but the hookfunction gets never called.

Solution: I'm now creating my own "notify process" which installes the hook and stays alive as long as the library is not expunged.

I set up the hook in libInit():

Code: Select all

	libBase->prefsHook = IExec->AllocSysObjectTags(ASOT_HOOK,
	                                               ASOHOOK_Entry, prefsUpdateHook,
	                                               ASOHOOK_Subentry, NULL,
	                                               TAG_DONE);
In libOpen() when the opencounter is one I setup the NotifyVar():

Code: Select all

success = libBase->IDOS->NotifyVar("TestVar", libBase->prefsHook, NV_GLOBAL_NOTIFY, libBase);
success is != FALSE (it's DOSTRUE)

The prefsUpdateHook() function is:

Code: Select all

void prefsUpdateHook(struct Hook *hook, CONST_APTR userdata, CONST_STRPTR name)
{
	struct LibraryBase *libBase = (struct LibraryBase *)userdata; 
#ifdef DEBUG
	libBase->IExec->DebugPrintF("Function prefsUpdateHook called\n");
	libBase->IExec->DebugPrintF("Function prefsUpdateHook userdata=%x\n", userdata);
	libBase->IExec->DebugPrintF("Function prefsUpdateHook name=%s\n", name);
#endif
	libBase->IExec->MutexObtain(libBase->lockMutex);
	readPrefs(libBase);
	libBase->IExec->MutexRelease(libBase->lockMutex);
}
But this doesn't work, why?

If I do the same in an stand alone program it works:

Code: Select all

#include <proto/exec.h>
#include <proto/dos.h>

void prefsUpdateHook(struct Hook *hook, CONST_APTR userdata, CONST_STRPTR name)
{
	IExec->DebugPrintF("Function prefsUpdateHook called\n");
	IExec->DebugPrintF("Function prefsUpdateHook userdata=%x\n", userdata);
	IExec->DebugPrintF("Function prefsUpdateHook name=%s\n", name);
}

int main(void)
{
	struct Hook *hook;
	int32 success;

	hook = IExec->AllocSysObjectTags(ASOT_HOOK,
	                                 ASOHOOK_Entry, prefsUpdateHook,
	                                 ASOHOOK_Subentry, NULL,
	                                 TAG_DONE);

	success = IDOS->NotifyVar("TestVar", hook, NV_GLOBAL_NOTIFY, (APTR)0xBAAAAAAD);
	if (success)
	{
		IExec->Wait(SIGBREAKF_CTRL_C);
	}

	IDOS->NotifyVar(NULL, hook, NV_REMOVE_NOTIFY, NULL);
	IExec->FreeSysObject(ASOT_HOOK, hook);

	return 0;
}

Re: Using IDOS->NotifyVar() in library?

Posted: Fri Aug 09, 2013 11:18 pm
by Rigo
Possibly because the library opener is a task, and as such cannot use dos functions like this?

Simon

Re: Using IDOS->NotifyVar() in library?

Posted: Sat Aug 10, 2013 12:07 am
by gazelle
Nope, I checked that:

Function libOpen Task=0x62A65640
Function libOpen ln_Type=13 (NT_PROCESS)

Re: Using IDOS->NotifyVar() in library?

Posted: Sat Aug 10, 2013 2:07 am
by colinw
I have just tested the variable notification function and it is working correctly.

Please test it by typing the following in a shell; setenv testvar xxx

Also, please tell me what dos library version you are using.

Re: Using IDOS->NotifyVar() in library?

Posted: Sat Aug 10, 2013 11:07 am
by gazelle
As I said, it works ok in an stand alone program but not inside my library.

Code: Select all

5.System:> version full exec.library
exec.library 53.39 (2012-12-13)
5.System:> version full dos.library 
dos.library 53.126 (2013-02-23)
5.System:> version full utility.library
utility.library 53.3 (2010-11-08)
5.System:> gcc -v
Using built-in specs.
Target: ppc-amigaos
Configured with: ../gcc/configure --prefix=/gcc --host=ppc-amigaos --target=ppc-amigaos --build=i686-cygwin --enable-haifa --enable-sjlj-exceptions --enable-languages=c,c++
Thread model: single
gcc version 4.2.4 (adtools build 20090118)
5.System:> 
This is a X1000 AmigaOS 4.1.6 with the latest updates, SDK version is 53.20.

I always tried with the "setenv" command to trigger the updatehook. I even made a small test programm which uses IDOS->SetVar().

Debugoutput:

Code: Select all

Function libInit called
Function libInit libBase=6FDC0CA8
Function libInit libBase->lockMutex = 6FFAA1E0
Function libInit libBase->prefsHook = 62AAC3A0
Function _main_Obtain called
Function libOpen called
Function libOpen Task=62A65640
Function libOpen ln_Type=13
Function libOpen ln_Name=Background CLI
Function openInterfaces called
Function openInterfaces IDOS=6FDA4170
Function openInterfaces IUtility=6FF8F000
Function readPrefs called
Function readPrefs imagePath=TBImages:
Function libOpen NotifyVar(testvar, 0x62AAC3A0, 256, 0x6FDC0CA8)=-1
Function libOpen libBase->prefsHook=62AAC3A0
Function libOpen libBase->prefsHook->h_Entry=7FFB39A8
Function libOpen libBase->prefsHook->h_SubEntry=0
Function libOpen libBase->prefsHook->h_Data=FFFFFFFF
Function prefsUpdateHook called
Function prefsUpdateHook userdata=6FDC0CA8
Function prefsUpdateHook name=testvar
Function readPrefs called
Function readPrefs imagePath=TBImages:
The "prefsUpdateHook called" commes from my own try to call the hook with:

Code: Select all

libBase->IUtility->CallHookPkt(libBase->prefsHook, (APTR)libBase, (APTR)"testvar");
I' compiling with:

Code: Select all

OPTIMIZE = # -O3
DEBUG    = -g -DDEBUG
CFLAGS   = -Wall -Werror -Wwrite-strings $(OPTIMIZE) $(DEBUG) \
           -D__NOLIBBASE__ -D__NOGLOBALIFACE__ -Iinclude

Re: Using IDOS->NotifyVar() in library?

Posted: Sat Aug 10, 2013 11:22 am
by trixie
@gazelle

It may not be helpful at all but what you're describing reminds me of a problem I once had. It turned out that it was because the main code and the hook stuff were executed on different contexts. The solution was to Signal() my task from the hook; I then processed the signal in my main event loop and did (now on the main context) what the hook would have done. It's possible that in your case, the hook gets called on the DOS.library context whereas your own library represents a different one. But what do I know, I'm just guessing.

Re: Using IDOS->NotifyVar() in library?

Posted: Sat Aug 10, 2013 11:34 am
by gazelle
@trixie

But the hook gets never called!

I have thought in that direction allready. Maybe I have to spawn my own process which then installes the notification and keep him alive until the library gets closed.

Re: Using IDOS->NotifyVar() in library?

Posted: Sat Aug 10, 2013 1:16 pm
by colinw
For this function, the hook is always called from a different context.

If the notification is added to the internal list, and the name matches,
the hook will be called from the process that is modifying the variable.

Be aware that if the process that initiated the notification ends,
and it still has notifications that havn't been terminated, the DOS cleanup
code will force the termination of all notifications created by that process
just before the process is finally deleted.

This is from the autodoc:

* WARNING
* For compatibility and resource tracking purposes, the same process
* that started any notifications, MUST be the same one that ends them.
*
* You MUST terminate all variable notifications that you started,
* before your program exits otherwise notifications will continue to
* vector until the process is completely deleted.

Re: Using IDOS->NotifyVar() in library?

Posted: Sat Aug 10, 2013 3:26 pm
by gazelle
I have no control over the calling process. I'll try another approach.

Solution: I'm now creating my own "notify process" which installes the hook and stays alive as long as the library is not expunged.

Simpler solution: Do it in libInit(). Then the calling process is "ramlib" and I don't have to spawn my own one because "ramlib" stays alive. Is this save?

Re: Using IDOS->NotifyVar() in library?

Posted: Sun Aug 11, 2013 12:23 am
by colinw
gazelle wrote:I have no control over the calling process. I'll try another approach.

Solution: I'm now creating my own "notify process" which installes the hook and stays alive as long as the library is not expunged.

Simpler solution: Do it in libInit(). Then the calling process is "ramlib" and I don't have to spawn my own one because "ramlib" stays alive. Is this save?
It is not REALLY safe per-se, there are a couple of things that can happen that may cause problems.
Such as; ramlib may auto-restart from a crash and that will take your notification down when the dead process hits DOS cleanup().
If your library does not stay disk based and is not loaded by the ramlib process, you could be called from a task context.

Your first idea is much better, just create a small dedicated async process that sits in Wait() until the library has the expunge
vector called, then signal it to exit, (and do actually make sure it exits in a robust way), expunge and return.

Also, in CreateNewProc() do specify the tags not required to limit default inheritance of pointless attributes, such as;
NP_CopyVars,FALSE, NP_CurrentDir,0, NP_ProgramDir,0, NP_Input,0, NP_Output,0, and give it a name with NP_Name
so it shows up with a descriptive name in the process list.