English Amiga Board


Go Back   English Amiga Board > Coders > Coders. System

 
 
Thread Tools
Old 23 July 2019, 23:01   #1
Rednael
Registered User

 
Join Date: May 2018
Location: The Netherlands
Posts: 30
Ending a message-loop properly

Hoping that this is posted in the right place, as I do have a question about the handling the OS's message-pump, but my code is in assembly.

Anyway, here goes...

I'm simply opening a window and then, when the close gadget is clicked, closing it again. My code is working, but there's something weird going on that I don't understand, and I hope someone can explain it to me... or point me to a bug

Here's the
Code:
;--------------------------------------
; Includes
;--------------------------------------
incdir  "inclAsmMrt:"
  
include "exec/exec.i"
include "exec/exec_lib.i"
include "intuition/intuition.i"
include "intuition/intuition_lib.i"

;--------------------------------------
; Code
;--------------------------------------
start:
  ;open intiution library
  lea  IntuitLibName,a1
  moveq  #36,d0  ;version 36
  CALLEXEC OpenLibrary
  tst.l  d0
  beq  end
  move.l  d0,_IntuitionBase

  ;open window
  lea  NewWindow_Main,a0  ;NewWindow struct
  CALLINT  OpenWindow
  tst.l  d0
  beq  end_intuit
  move.l  d0,Window_Main

  ;- - - - - - - - - - -
  ; start message-loop
  ;- - - - - - - - - - -
  
  ;get the window's userport
  movea.l  Window_Main,a0
  movea.l  wd_UserPort(a0),a0
  move.l  a0,UserPort_Main
  
wait_for_msg:
  ;wait for message
  movea.l  UserPort_Main,a0
  CALLEXEC WaitPort
  tst.l  d0
  beq  wait_for_msg
check_msg_type:
  ;get the message's class
  exg  d0,a1
  move.l  im_Class(a1),d5  
  ;discard the message
  CALLEXEC ReplyMsg
  ;check for close-window message
  cmpi.l  #IDCMP_CLOSEWINDOW,d5
  beq  close_window
get_msg:
  ;get next message
  movea.l  UserPort_Main,a0
  CALLEXEC GetMsg
  tst.l  d0
  beq  wait_for_msg
  bra  check_msg_type
  
  ;- - - - - - - - - - -
  ; end message-loop
  ;- - - - - - - - - - -
  
close_window:
  ;discard all remaining messages
  movea.l  UserPort_Main,a0
  CALLEXEC GetMsg
  tst.l  d0
  beq   do_close
  exg  d0,a1
  CALLEXEC ReplyMsg   ;<<<<<<<<<<<
  bra  close_window
do_close:
  ;close the window
  movea.l  Window_Main,a0
  CALLINT  CloseWindow

end_intuit:
  ;close intuition library
  movea.l  _IntuitionBase,a1
  CALLEXEC CloseLibrary

end:
  ;exit with success
  clr.l  d0
  rts

;--------------------------------------
; Data
;--------------------------------------

;libraries
even
_IntuitionBase:  dc.l  0
IntuitLibName:  INTNAME

;main window
even
Window_Main:  dc.l  0
UserPort_Main:  dc.l  0
NewWindow_Main:
    dc.w  10  ;left
    dc.w  10  ;top
    dc.w  250  ;width
    dc.w  100  ;height
    dc.b  1  ;detail pen
    dc.b  2  ;block pen
    dc.l  IDCMP_CLOSEWINDOW  ;idcmp flags
    dc.l  WFLG_SIZEGADGET+WFLG_CLOSEGADGET+WFLG_DRAGBAR+WFLG_DEPTHGADGET+WFLG_ACTIVATE  ;flags
    dc.l  0  ;ptr to first gadget (in node list)
    dc.l  0  ;ptr to checkmark images
    dc.l  WinTitle_Main  ;ptr to title
    dc.l  0  ;ptr to screen
    dc.l  0  ;ptr to bitmap struct
    dc.w  20  ;min width
    dc.w  20  ;min height
    dc.w  600  ;max width
    dc.w  300  ;max height
    dc.w  1  ;type (screen) 1=WB,2=Publ,F=Custm
even
WinTitle_Main:  dc.b  "Hi World!",0

;--------------------------------------
So, the code runs fine up to the close_window label.
The issue arises when discarding left-over messages in close_window.

I have three scenarios:
1. Don't discard any message -> prog hangs at: CALLINT CloseWindow
2. Discard all messages using CALLEXEC ReplyMsg -> Every reply seems to trigger a new message, resulting in an infinite loop
3. Discard all messages without calling CALLEXEC ReplyMsg -> success!

One additional thing... in scenario 2, when I click the close gadget exactly three times, the prog exits the infinite loop and closes the window nicely.

I just don't get it. Am I doing something wrong?
Shouldn't I call ReplyMsg? But if I don't then how does the OS know when to free the messages?
And why do I get stuck in an infinite loop when I do reply to the messages?
And what's up with clicking the close gadget three times?

I could use some on this.
Rednael is offline  
Old 23 July 2019, 23:24   #2
Hedeon
PPC Hacker

 
Join Date: Mar 2012
Location: Leiden / The Netherlands
Posts: 1,084
Not sure if it is the problem, but WaitPort does not remove the first message from the queue. So you are handling it twice. (d0 from WaitPort then ReplyMsg-ing it, followed by GetMsg and ReplyMsg-ing it again).

So you do a first GetMsg() after the WaitPort() and then handle that message.

From the RKM:

FUNCTION
This function waits for the given port to become non-empty. If
necessary, the Wait() function will be called to wait for the port
signal. If a message is already present at the port, this function
will return immediately. The return value is always a pointer to
the first message queued (but it is not removed from the queue).
Hedeon is offline  
Old 24 July 2019, 19:59   #3
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 275
Quote:
Originally Posted by Rednael View Post
I just don't get it. Am I doing something wrong?
Shouldn't I call ReplyMsg? But if I don't then how does the OS know when to free the messages?
And why do I get stuck in an infinite loop when I do reply to the messages?
And what's up with clicking the close gadget three times?

I could use some on this.

First, as already stated, WaitForPort() only checks whether the port has any messages pending, but it does not remove them from the port. GetMsg() does. So the typical event loop looks like this:
Code:
do {
 WaitPort(port);
msg = GetMsg(port);
... handle message ...
ReplyMsg(msg);
} while(!quit);

There is no need to be afraid that messages are still pending in the IDCMP port of the window will "leak". Intuition is aware of the race condition, and removes them before deleting the window. Actually, they are not "released", but recycled for another program or another event.
Thomas Richter is offline  
Old 24 July 2019, 22:51   #4
Rednael
Registered User

 
Join Date: May 2018
Location: The Netherlands
Posts: 30
Quote:
Originally Posted by Hedeon View Post
Not sure if it is the problem, but WaitPort does not remove the first message from the queue. So you are handling it twice.
Oh wow, thanks for pointing that out. And there I was, thinking I could do it better then all the examples

It doesn't seem to fix all issues though, but it does fix the click 3 times issue.
Will test it further when I'm back at my Amiga.
Rednael is offline  
Old 24 July 2019, 22:54   #5
Rednael
Registered User

 
Join Date: May 2018
Location: The Netherlands
Posts: 30
Quote:
Originally Posted by Thomas Richter View Post
There is no need to be afraid that messages are still pending in the IDCMP port of the window will "leak". Intuition is aware of the race condition, and removes them before deleting the window. Actually, they are not "released", but recycled for another program or another event.
Ah, another WOW! That's actually better, as that means I can just remove all the code that produces the issues.

This is very useful info. Where do you get this? Any good readings? I would really like to read up on Intuition. There doesn't seem to be much info.
Rednael is offline  
Old 25 July 2019, 13:30   #6
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 275
Quote:
Originally Posted by Rednael View Post
This is very useful info. Where do you get this?
Well, there are certainly a couple of problems with the Os, but that's none. It is kind of obvious that intuition has to do something about the problem as you can call "CloseWindow()" any time, and this shouldn't cause races either. So, it is kind of obvious that something has to happen about this in intuition. Other than that, well,... in my case it is matter of "Use the source, Luke!".
Quote:
Originally Posted by Rednael View Post
Any good readings? I would really like to read up on Intuition. There doesn't seem to be much info.
Well... The Rom Kernel Reference Manuals are certainly the best information you can get, and you find them online these days. They contain example programs that demonstrate how things work. I would suggest looking there.
Thomas Richter is offline  
Old 28 July 2019, 18:08   #7
Rednael
Registered User

 
Join Date: May 2018
Location: The Netherlands
Posts: 30
Hmm, still having issues. After removal of the code that discards all existing messages, it now hangs when closing the window.
If I don't need to free any messages after IDCMP_CloseWindow, why does it freeze up now?

Here's my current
Code:
;--------------------------------------
;PRINTV start
;ADDWATCH start
;ADDWATCH close_window
;ADDWATCH end_intuit

;--------------------------------------
; Includes
;--------------------------------------
incdir	"inclAsmMrt:"
	
include "exec/exec.i"
include "exec/exec_lib.i"
include "intuition/intuition.i"
include	"intuition/intuition_lib.i"

;--------------------------------------
; Code
;--------------------------------------
start:
	;open intiution library
	lea	IntuitLibName,a1
	moveq.l	#36,d0			;version 36
	CALLEXEC OpenLibrary
	tst.l	d0
	beq	end
	move.l	d0,_IntuitionBase

	;open window
	lea	NewWindow_Main,a0
	CALLINT	OpenWindow
	tst.l	d0
	beq	end_intuit
	move.l	d0,Window_Main

	;- - - - - - - - - - -
	; start message loop
	;- - - - - - - - - - -

	;get the window's userport
	movea.l	Window_Main,a0
	movea.l	wd_UserPort(a0),a0
	move.l	a0,UserPort_Main
	
wait_for_msg:
	;wait form message on userport
	movea.l	UserPort_Main,a0
	CALLEXEC WaitPort
	tst.l	d0
	beq	wait_for_msg
get_msg:
	;get (next) message from queue
	CALLEXEC GetMsg
	tst.l	d0
	beq	wait_for_msg
check_msg_type:
	;get message's properties
	exg	d0,a1
	move.l	im_Class(a1),d5
	;close the message
	CALLEXEC ReplyMsg
	;check for actions on message
	cmpi.l	#IDCMP_CLOSEWINDOW,d5
	beq	close_window
	;check for more messages
	bra	get_msg

	;- - - - - - - - - -
	; end message loop
	;- - - - - - - - - -

close_window:
	movea.l	Window_Main,a0
	CALLINT	CloseWindow

end_intuit:
	;close intuit library
	movea.l	_IntuitionBase,a1
	CALLEXEC CloseLibrary

end:
	;exit with success
	clr.l	d0
	rts

;--------------------------------------
; Data
;--------------------------------------

;libraries
even
_IntuitionBase:	dc.l	0
IntuitLibName:	INTNAME

;main window
even
Window_Main:	dc.l	0
UserPort_Main:	dc.l	0

NewWindow_Main:
		dc.w	10	;left
		dc.w	10	;top
		dc.w	250	;width
		dc.w	100	;height
		dc.b	1	;detail pen
		dc.b	2	;block pen
		dc.l	IDCMP_CLOSEWINDOW	;idcmp flags
		dc.l	WFLG_SIZEGADGET+WFLG_CLOSEGADGET+WFLG_DRAGBAR+WFLG_DEPTHGADGET+WFLG_ACTIVATE	;flags
		dc.l	0	;ptr to first gadget (in node list)
		dc.l	0	;ptr to checkmark images
		dc.l	WinTitle_Main	;ptr to title
		dc.l	0	;ptr to screen
		dc.l	0	;ptr to bitmap struct
		dc.w	20	;min width
		dc.w	20	;min height
		dc.w	600	;max width
		dc.w	300	;max height
		dc.w	1	;type (screen) 1=WB,2=Publ,F=Custm
even
WinTitle_Main:	dc.b	"Hi World!",0

;--------------------------------------
I'm coding on the amiga in AsmPro. Debugging crashes also. Not when I close the window, but when I start the debugger
Perhaps I'm doing something wrong there too. Anyone's got some experience with AsmPro debugger? It doesn't seem to understand the ADDWATCH command neither.

(still developing on the Amiga itself is really nice)
Rednael is offline  
Old 28 July 2019, 18:10   #8
Rednael
Registered User

 
Join Date: May 2018
Location: The Netherlands
Posts: 30
Another quick question...
When calling library functions of exec and intuition, are the registers always preserved (except for the return values)?
Rednael is offline  
Old 28 July 2019, 19:02   #9
mark_k
Registered User
 
Join Date: Aug 2004
Location:
Posts: 3,110
Typically, OS functions preserve all registers except D0, D1, A0 and A1. However that can vary; read the autodoc for each function to be sure.

In your code example you assume that WaitPort() preserves register A0, but I don't think it does. A0 could contain anything when you call GetMsg().
mark_k is offline  
Old 28 July 2019, 19:16   #10
alkis
Registered User

 
Join Date: Dec 2010
Location: Athens/Greece
Age: 48
Posts: 494
Doesn't freeze on me. I assembled with vasm and run it from cli. Works as designed, I think
So, try making an executable and run it from cli.

When you call OS functions, a0-a1/d0-d1 are trash registers, all other registers saved. There are a few functions that preserve all registers but that's clearly stated on the autodocs. (e.g. WaitBlit)
alkis is offline  
Old 28 July 2019, 21:27   #11
a/b
Registered User

 
Join Date: Jun 2016
Location: europe
Posts: 127
Works for me in asm-one.
How do you run it, from cli or wb? You don't have proper startup code for wb, so maybe that's the reason.
Try this, it works for me in asm-one, cli, and wb.
Code:
; additional incude for process struct
	INCLUDE	dos/dosextens.i

start:
****   INSERT THIS AFTER LABEL start:
AbsExecBase		EQU	4

	move.l	(AbsExecBase).w,a6
	sub.l	a1,a1
	jsr	(_LVOFindTask,a6)
	move.l	d0,a2
	moveq	#0,d5
	tst.l	(pr_CLI,a2)
	bne.b	.FromCLI
.FromWB
	lea	(pr_MsgPort,a2),a0
	jsr	(_LVOWaitPort,a6)
	lea	(pr_MsgPort,a2),a0
	jsr	(_LVOGetMsg,a6)
	move.l	d0,d5
.FromCLI
****
	;open intiution library
...


end:
****   INSERT THIS AFTER LABEL end:
	tst.l	d5
	beq.b	.NoMsg
	jsr	(_LVOForbid,a6)
	move.l	d5,a1
	jsr	(_LVOReplyMsg,a6)
.NoMsg
****
	;exit with success
...
a/b is offline  
Old 28 July 2019, 21:28   #12
Rednael
Registered User

 
Join Date: May 2018
Location: The Netherlands
Posts: 30
Quote:
Originally Posted by mark_k View Post
In your code example you assume that WaitPort() preserves register A0, but I don't think it does. A0 could contain anything when you call GetMsg().
Yesssss! That worked! Perfect.

So, I'll considder d0,d1,a0,a1 as trashed registers. Thanks everyone.
Rednael is offline  
Old 28 July 2019, 21:35   #13
Rednael
Registered User

 
Join Date: May 2018
Location: The Netherlands
Posts: 30
Quote:
Originally Posted by a/b View Post
You don't have proper startup code for wb, so maybe that's the reason.
What is your code for?
Is it to make the program runnable from CLI as well as WB?


From what I've learned so far, there's no need to "free" messages at application's end. So the Forbid and ReplyMsg should not be needed.
Rednael is offline  
Old 28 July 2019, 21:50   #14
a/b
Registered User

 
Join Date: Jun 2016
Location: europe
Posts: 127
Yeah, it's to make it work from WB, in which case the first thing you receive is a love letter from WB and if you don't reply at the end, it will dump your program and bad things will happen.
a/b is offline  
Old 02 August 2019, 20:58   #15
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 275
If you don't reply in the end, the workbench will never unload your program and you have a memory leak.
Thomas Richter is offline  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
WinUAE stuck in a loop Leandro Jardim support.WinUAE 2 07 April 2018 22:38
It Came from the Desert crashing in a Loop gb_pdx support.FS-UAE 5 04 January 2017 21:43
Copper loop confusions Fell Coders. Asm / Hardware 15 21 September 2015 22:02
fastest possible rom copy loop Yulquen74 Coders. Asm / Hardware 17 10 May 2014 20:10
Sampled loop in cracktro absence request.Music 2 30 June 2012 12:33

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 07:39.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2019, vBulletin Solutions Inc.
Page generated in 0.08067 seconds with 15 queries