Re: got it to work!

Paul Chen (chen@geoworks.com)
Thu, 2 Jan 1997 10:24:14 -0800 (PST)

Edward Di Geronimo writes:
> Hi everyone,
>
> I finally got it to work! To get it to work, I had to make a predefined
> visMoniker inside the object block I was duplicating and putting the new
> item in, and tell the item to use it, and then replace the moniker with
> text. I think that the replace moniker message tries to free the old moniker
> first, and it couldn't handle not having a moniker. I haven't run this past
> swat yet, but it worked in Ensemble. Next task is to get it working in two
> threads.

Glad you found the problem. Sorry I wasn't in New Year's Day. Here's
an article from our Knowledge Database on how to handle stack overflows.

Incidentally, our Knowledge Database is available on our Web site --
go to the Geoworks Home Page, www.geoworks.com, then click on Developer
Relations --> Technical Support --> Knowledge Base. You can enter
search keywords and retrieve relevant articles, or you can browse the
entire database. This information may help you find answers to your
problems more quickly.


Here then is an article on fixing stack overflows:

Summary: Fixing STACK_OVERFLOW
Keywords: STACK_OVERFLOW stack dgroup
Access: ALL:PUBLIC
History: 960828 chen,961023 ryanh,961120 stevem

If you are experiencing "death due to STACK_OVERFLOW", you can use the
backtrace command in Swat to view the stack usage. In Swat, stop in
the method/routine you are concerned about and type "backtrace -rsp"
this means "show register sp for each stack frame in the backtrace".
When analyzing the stack usage, you should be concerned by any large
changes in the sp value between frames, and by sp's value nearing about
250.

There are several ways to fix the stack usage problem. Here are some
considerations.

1) Reducing the size of local variables
==========================================================

If your routine/method has large local arrays or structures in it,
you should consider moving the array/structure to a global data
block or allocating a block dynamically (using MemAlloc). This
concern is due to the fact that local variables are stored on the
stack, so large local variables will eat up lots of stack space.

Example:
--------
This code creates a local variable of 2 bytes to hold the handle
of a block that contains a 200-byte character string, rather than
creating a local variable to hold the string itself (char myStr[200]).

Also, the handle is passed to another routine, instead of passing
the string itself.

@method MyProcessClass, MSG_MY_MSG
{
MemHandle myStrHandle;
char *myStr;

myStrHandle = MemAlloc(200, HF_FIXED, HAF_LOCK);

if ( myStrHandle == NullHandle )
{
return(-1); /* return error */
}
else
{
myStr = MemDeref(myStrHandle);

/* ... perform your code here. */

AnotherRoutineThatNeedsTheString(myStrHandle);

MemFree(myStrHandle);
return(0); /* return okay */
}
}

2) forceQueue'ing messages
==========================================================

For messages that are deeply embedded, @send the message with the
"forceQueue" flag. This assures that the message will be placed on
the message queue, so it will have the full stack space when it is
Bhandled. The syntax is: "@send, forceQueue MyObject::MSG_MY_MSG".

The reason for the forceQueue flag is that if the destination
object is run by the same thread as the calling object, then the
sent message will be handled immediately as if it were an @call.
The forceQueue flag compels the system to always put the event on
the thread's message queue so it won't be executed until after the
current code (and all the code frames on the stack) return, and
after any other events that are already on the queue have returned.
This gives the queued message the entire stack to work with.

If the message to send is somewhat time-critical, you can also add the
flag insertAtFront, which puts the event at the start of the queue,
so it gets executed before any other events in the queue.

Note that the forceQueue flag cannot be used with @call.

3) Avoid deeply-nested routine calls
==========================================================

Similar to 2) above, deeply nested routine calls will eat away at
the stack. Try to arrange your code to avoid this -- perhaps by
sending message (using @send, forceQueue instead), or by rearranging
how your code is called, to more routines are called from a higher
level.

4) Increasing the size of the UI stack (this only works for
applications, not for libraries)
==========================================================

As a final option (and this should only be used as a last resort), you
can increase the size of the stacks for each thread in your application.

To change the stack size of your application's process thread, use the
"stack" keyword in your .gp file:

stack 3000

The parameter is in bytes; the default is 2000 bytes.

To change the stack size of your application's ui thread, subclass
MSG_PROCESS_CREATE_UI_THREAD as follows:

@method MyProcessClass, MSG_PROCESS_CREATE_UI_THREAD
{
stackSize = 3000; /* set new stack size to 3000 bytes */
@callsuper();
}

You should use backtrace to determine the minimum increase that you
need to make to the stack.