delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2004/05/17/06:30:20

X-Authentication-Warning: delorie.com: mail set sender to djgpp-bounces using -f
From: "Lawrence Rust" <nospam AT NOsoftsystemSPA DOT coM DOT uk>
Newsgroups: comp.os.msdos.djgpp
Subject: Re: Task switch with SIGALRM
Date: Mon, 17 May 2004 12:14:53 +0200
Organization: Software Systems
Lines: 155
Message-ID: <c8a3oo$rso$1@news-reader5.wanadoo.fr>
References: <Pine DOT GSO DOT 4 DOT 58 DOT 0405170936310 DOT 4679 AT ural2>
NNTP-Posting-Host: mix-poitiers-105-3-206.w193-250.abo.wanadoo.fr
X-Trace: news-reader5.wanadoo.fr 1084789336 28568 193.250.33.206 (17 May 2004 10:22:16 GMT)
X-Complaints-To: abuse AT wanadoo DOT fr
NNTP-Posting-Date: 17 May 2004 10:22:16 GMT
X-Priority: 3
X-MSMail-Priority: Normal
X-Newsreader: Microsoft Outlook Express 5.50.4927.1200
X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4927.1200
To: djgpp AT delorie DOT com
DJ-Gateway: from newsgroup comp.os.msdos.djgpp
Reply-To: djgpp AT delorie DOT com

I believe that your problems arise from using an uninitialised stack for the
additional threads.  The DJGPP runtime library makes assumptions about the
relationship of certain CPU registers especially for the handling of C++
exceptions.

It may prove useful to look at the source for setjmp and longjmp to see
what's needed.  IMHO it's probably easier to use setjmp and longjmp to
switch between threads since these routines already handle the complexity.
E.g.:

void* MTC_PlatformSwitchStack( void* pvStack);
typedef struct SThread
  {
  MTC_Thread thread;
  /* Context */
  jmp_buf jbuf;
  double stack[ 1];        /* NB variable length */
  } SThread;

/*
 * Allocate a thread instance
 */
struct MTC_Thread* MTC_PlatformThreadAlloc( size_t size)
  {
  /* C99 7.13.2.3: After setjmp, auto vars not qualified by volatile have
   * indeterminate value */
  auto struct SThread* volatile pThread;

  /* Set stack size */
  if ( size < 4096 && size != 1)
    size = s_uStackSize;

  /* Allocate instance data plus stack */
  pThread = (SThread*) MTC_PlatformMalloc( sizeof( SThread) + size );
  if ( NULL == pThread)
    return NULL;

  if ( 1 != size) /* 'main' thread is 'created' with a stack size of 1 */
    {
    static struct SThread* s_pThread;
    static void* s_SP;

    /* Switch to new stack */
    s_pThread = pThread;
    s_SP = MTC_PlatformSwitchStack( (char*)(pThread->stack) + size );
    /* NB auto vars no longer accessible */

    /* NB setjmp must be called inline otherwise the new thread's stack
     * will be corrupted after the return
     * C99 7.13.1.1: setjmp is a macro and a reserved identifier
     */
    if ( 0 != setjmp( s_pThread->jbuf) )
      {
      /* NB Do not use local vars */
      /* Run the current thread */
      MTC_ThreadExecute();

      /* Should never get here */
      MTC_ASSERT( !"Zombie thread");
      }

    /* Restore stack */
    (void)MTC_PlatformSwitchStack( s_SP);
    /* auto vars now accessible */
    }

  return &pThread->thread;
  }

/*
 * Switch stacks
 */
asm ( /* NB __volatile not supported outside of function body */
  /*".globl _MTC_PlatformSwitchStack\n"*/
  "_MTC_PlatformSwitchStack:\n"
  "popl %edx\n" /* return address */
  "popl %eax\n" /* pvStack */
  "subl $4, %eax\n"
  "xchgl %eax, %esp\n" /* NB assume SS=DS */
  "jmp *%edx"
);

/*
 * Suspend a thread and dispatch the next runnable thread
 */
void MTC_PlatformThreadSwitch(
  struct MTC_Thread* hThread,
  struct MTC_Thread* hNextThread
) {
  /* Save current context */
  if ( NULL == hThread
    || 0 == setjmp( MTC_CONTAINER( hThread, SThread, thread)->jbuf )
  ) {
    /* Restore context for next runnable thread */
    longjmp( MTC_CONTAINER( hNextThread, SThread, thread)->jbuf, 1);
    }
  }


NB the DJGPP signal handler doesn't save the FPU state so you will need to
do this yourself in your signal handler if any threads use floating point.
E.g.

    char fpbuf[128]; /* FPU save buffer */

    /* Save FPU state */
    __asm__ __volatile ( "fnsave %0\n" : "=g" (fpbuf) );

    /* Restore FPU state */
    __asm__ __volatile ( "frstor %0\n" : "=g" (fpbuf) );

HTH

-- Lawrence Rust, Software Systems, www.softsystem.co.uk


"Gabriel Zoltan" <gz331 AT hszk DOT bme DOT hu> wrote in message
news:Pine DOT GSO DOT 4 DOT 58 DOT 0405170936310 DOT 4679 AT ural2...
> Hi!
>
> I'm trying to implement a small real-time kernel. I previously tried to
> switch tasks from timer interrupts, but then I realised based on the
> mailing list that it's not going to work. Now I try to do it using
> signals.
> Sadly it still won't work :(. I use setitimer() and signal(). The signal
> handler function looks like this:
>
> _Handler:
>   cli
>   pushal
>
>   movl %esp, _tos_task
>
>   call _TickHandler
>
>   movl _tos_task, %esp
>
>   popal
>   sti
>   ret
>
> Here _tos_task is the top of stack for the task, which gets changed during
> _TickHandler appropriately (the stack for the previous task is saved, and
> then the variable is loaded with the new task's stack value).
> My problem is that tasks run OK for the first time, but when the scheduler
> tries to run them again, the system crashes (with various reasons:
> stack fault, GPF). Also if there is no stack switch it runs OK (_tos_task
> doesn't get changed in tickhandler).
> Do you have an idea what I'm doing wrong?
>
> Thanks for your help.
>
> Zoltan


- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019