www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2002/01/25/01:53:34

X-Authentication-Warning: delorie.com: mailnull set sender to djgpp-bounces using -f
Message-ID: <0BA32251E589D2118EA60008C70DDCAB025F9187@JNJFRISEXS1.eu.jnj.com>
From: "Baribaud, Christophe [JNJFR]" <CBARIBAU AT jnjfr DOT JNJ DOT com>
To: "'Eli Zaretskii'" <eliz AT is DOT elta DOT co DOT il>,
"Baribaud, Christophe [JNJFR]"
<CBARIBAU AT jnjfr DOT JNJ DOT com>
Cc: djgpp AT delorie DOT com
Subject: RE: multi-threading
Date: Fri, 25 Jan 2002 07:49:47 +0100
MIME-Version: 1.0
X-Mailer: Internet Mail Service (5.5.2655.55)
Reply-To: djgpp AT delorie DOT com

This message is in MIME format. Since your mail reader does not understand
this format, some or all of this message may not be legible.

------_=_NextPart_000_01C1A56C.7AB04D30
Content-Type: multipart/alternative;
	boundary="----_=_NextPart_001_01C1A56C.7AB04D30"


------_=_NextPart_001_01C1A56C.7AB04D30
Content-Type: text/plain

I don't succeed in sending messages to newsgroup including files ;-((
So I send it to you

Here is the pre-alpha version of minimalistic multi-threading routines, if
it is of some interest for anybody :-)

Regards
CB

-----Message d'origine-----
De : Eli Zaretskii [mailto:eliz AT is DOT elta DOT co DOT il]
Envoye : jeudi 24 janvier 2002 11:17
A : Christophe BARIBAUD
Cc : djgpp AT delorie DOT com
Objet : Re: multi-threading



On Thu, 24 Jan 2002, Christophe BARIBAUD wrote:

> I am currently trying to build a minimalistic multi-threaded kernel with
> djgpp.
> When I change stack selector (ss) my programs hangs when calling
__dpmi_int
> It **seems** that DJGPP assumes SS=DS in order to function correctly.
> 
> Can anybody confirm this ?

Yes, the code produced by GCC assumes DS=SS=ES.

If you change the SS to implement the multithreading, you will either 
have to find another way, or do that in assembly.


------_=_NextPart_001_01C1A56C.7AB04D30
Content-Type: text/html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=us-ascii">
<META NAME="Generator" CONTENT="MS Exchange Server version 5.5.2654.45">
<TITLE>RE: multi-threading</TITLE>
</HEAD>
<BODY>

<P><FONT SIZE=2>I don't succeed in sending messages to newsgroup including files ;-((</FONT>
<BR><FONT SIZE=2>So I send it to you</FONT>
</P>

<P><FONT SIZE=2>Here is the pre-alpha version of minimalistic multi-threading routines, if it is of some interest for anybody :-)</FONT>
</P>

<P><FONT SIZE=2>Regards</FONT>
<BR><FONT SIZE=2>CB</FONT>
</P>

<P><FONT SIZE=2>-----Message d'origine-----</FONT>
<BR><FONT SIZE=2>De : Eli Zaretskii [<A HREF="mailto:eliz AT is DOT elta DOT co DOT il">mailto:eliz AT is DOT elta DOT co DOT il</A>]</FONT>
<BR><FONT SIZE=2>Envoye : jeudi 24 janvier 2002 11:17</FONT>
<BR><FONT SIZE=2>A : Christophe BARIBAUD</FONT>
<BR><FONT SIZE=2>Cc : djgpp AT delorie DOT com</FONT>
<BR><FONT SIZE=2>Objet : Re: multi-threading</FONT>
</P>
<BR>
<BR>

<P><FONT SIZE=2>On Thu, 24 Jan 2002, Christophe BARIBAUD wrote:</FONT>
</P>

<P><FONT SIZE=2>&gt; I am currently trying to build a minimalistic multi-threaded kernel with</FONT>
<BR><FONT SIZE=2>&gt; djgpp.</FONT>
<BR><FONT SIZE=2>&gt; When I change stack selector (ss) my programs hangs when calling __dpmi_int</FONT>
<BR><FONT SIZE=2>&gt; It **seems** that DJGPP assumes SS=DS in order to function correctly.</FONT>
<BR><FONT SIZE=2>&gt; </FONT>
<BR><FONT SIZE=2>&gt; Can anybody confirm this ?</FONT>
</P>

<P><FONT SIZE=2>Yes, the code produced by GCC assumes DS=SS=ES.</FONT>
</P>

<P><FONT SIZE=2>If you change the SS to implement the multithreading, you will either </FONT>
<BR><FONT SIZE=2>have to find another way, or do that in assembly.</FONT>
</P>

<P><FONT FACE="Arial" SIZE=2 COLOR="#000000"></FONT><FONT FACE="Arial" SIZE=2 COLOR="#000000"></FONT>&nbsp;

</BODY>
</HTML>
------_=_NextPart_001_01C1A56C.7AB04D30--

------_=_NextPart_000_01C1A56C.7AB04D30
Content-Type: application/octet-stream;
	name="TASK.C"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="TASK.C"

#include <stdio.h> // Just for thread sample
#include <math.h>  // Just for thread sample

/*
** Simple non-preemptive multi-tasking routines v0.0
** Christophe BARIBAUD (cbaribau AT jnjfr DOT jnj DOT com)
** Jan 2002
**
** This is a **draft**
** These routines have been tested under MS-DOS 6.22 and Windows 2000
** using DJGPP v2.03
*/

// MAX_THREAD : maximum number of threads
// It may have any value, but the actual stack space of any thread
// is _stklen/MAX_THREAD
// This implementation doesn't check stack overflow, so be careful...
#define MAX_THREAD 4

struct InternalThread
{
  char *sp;             // Stack pointer of thread
  int status;           // 0 =3D free, 1 =3D running
};

extern long _stklen; // Size of stack allocated by DJGPP, may be =
changed
struct InternalThread InternalThreadTable[MAX_THREAD];
int CurrentThread;

// Globals needed to communicate with assembler part
char *Yield_vesp;
char **Yield_esp;
void (*Yield_start)(void);

//
// InitializeThreads
//
// This routine must be called before any call to thread routines
//
void InitializeThreads(void)
{
  // First of all, let retreive existing stack space
  asm("movl %ss,_Yield_vesp"); // get current stack selector into =
Yield_vesp
  //printf("Stack selector : %lx\r\n",Yield_vesp);
  unsigned short buffer[4];
  if (__dpmi_get_descriptor(Yield_vesp,(void*)buffer) =3D=3D -1)
  {
    printf("Unable to retieve stack selector informations\r\n");
    exit(-1);
  }
  // Now we compute segment limit. Cf. dpmi documentation
  unsigned long StackSize =3D buffer[0]; // segment limit field
  StackSize |=3D ((buffer[3] & 0x000F)<<16); // 4 high order bits
  if ((buffer[3] & 0x0080) !=3D 0) //  page granular
    StackSize =3D StackSize << 12;
  printf("Total stack space : =
[%lx:%lx]\r\n",StackSize-_stklen,StackSize);
  // Stack space is between StackSize-_stklen and StackSize
  int i;
  for (i=3D0;i<MAX_THREAD;i++)
  {
    InternalThreadTable[i].sp =3D (char*)StackSize;
    InternalThreadTable[i].status =3D 0; // free
    StackSize -=3D (_stklen/MAX_THREAD); // every thread owns its part =
of total stack
  }
  CurrentThread =3D 0; // 0 =3D main thread
  InternalThreadTable[CurrentThread].status =3D 1; // main thread is =
already running

  for (i=3D0;i<MAX_THREAD;i++)
  {
    printf("Thread stack %d : %lx\r\n",i,InternalThreadTable[i].sp);
  }
}

//
// CreateThread
//
// This routine creates a new thread, starting at 'start'
// It returns new thread identifier or a negative value on error
//

int CreateThread(void (*start)(void))
{
  int i;
  for (i=3D0;i<MAX_THREAD && InternalThreadTable[i].status !=3D 0;i++);
  if (i =3D=3D MAX_THREAD)
    return -1; // Task table full
  struct InternalThread *t =3D &InternalThreadTable[i];
  Yield_vesp =3D t->sp;
  t->status =3D 1; // new thread is supposed to be alive...
//  printf("Task stack entry : %lx\r\n",Yield_vesp);
 =20
  Yield_start =3D start;
  Yield_esp =3D &InternalThreadTable[CurrentThread].sp;
  CurrentThread =3D i; // SwitchTaskJump jumps into new thread
  SwitchTaskJump();
  return i;
}

//
// Yield
//
// This routine yields control to next running thread
// It should be used when a thread waits for an event (keyboard, com, =
...)
// and sometimes during long operations
// Sadly, it is not possible to insert it in DOS wait operations like =
disk access
//

void Yield(void)
{
  struct InternalThread *from,*to;
  from =3D &InternalThreadTable[CurrentThread];
  to =3D 0;
  int i;
  for (i=3D0;i<MAX_THREAD && !to;i++)
  {
    int j =3D (i + CurrentThread + 1) % MAX_THREAD;
    if (InternalThreadTable[j].status =3D=3D 1) // this thread is alive
    {
      to =3D &InternalThreadTable[j];
      CurrentThread =3D j; // not yet ...
    }
  }
  if (!to)
  {
    printf("PANIC : no thread left\r\n");
    exit(-1);
  }
  // Now, we plan to switch from "from" to "to" thread
  Yield_esp =3D &from->sp;
  Yield_vesp =3D to->sp;
  SwitchTask(); // switch!
}

//
// KillMyThread
//
// Nobody is supposed to call this routine directly
// It is called when a thread returns from its start routine
// Then, current thread is deleted
//

void KillMyThread(void)
{
  // If I got there, a thread returns from its start function
  if (CurrentThread =3D=3D 0)
  {
    printf("PANIC : trying to kill main thread\r\n");
    exit(-1);
  }
  //printf("Thread %d is dying...\r\n",CurrentThread);
  InternalThreadTable[CurrentThread].status =3D 0; // current thread is =
dead
  Yield(); // resume another thread
}

void thread1(void) // thread sample 1
{
  int i;
  for (i=3D0;i<1000;i++)
  {
    printf("Thread 1 : %d %f\r\n",i,cos(i));
    Yield();
  }
}

void thread2(void) // thread sample 2
{
  int i;
  for (i=3D0;i<10;i++)
  {
    printf("Thread 2 : %d %f\r\n",i,sin(i));
    Yield();
  }
}

// Demo program
int main()
{
  InitializeThreads(); // Needed before any call to thread routines
  CreateThread(thread1);
  CreateThread(thread2);
  int i;
  for (i=3D0;i<30;i++) // Loops 30 times threads and exit
  {
    printf("Main thread\r\n");
    Yield();
  }
}

------_=_NextPart_000_01C1A56C.7AB04D30
Content-Type: application/octet-stream;
	name="TASKASM.S"
Content-Disposition: attachment;
	filename="TASKASM.S"

/*
** Simple non-preemptive multi-tasking routines v0.0
** Christophe BARIBAUD (cbaribau AT jnjfr DOT jnj DOT com)
** Jan 2002
** Assembler part : save context, restore context and juggle with
** stack pointer
*/

.globl  _SwitchTask
_SwitchTask:
        pushl      %eax
        pushl      %ebx
        pushl      %ecx
        pushl      %edx
        pushl      %ebp
        pushl      %edi
        pushl      %esi
        movl       _Yield_esp,%eax
        movl       %esp,(%eax)
        movl       _Yield_vesp,%esp
        popl       %esi
        popl       %edi
        popl       %ebp
        popl       %edx
        popl       %ecx
        popl       %ebx
        popl       %eax
        ret
.globl  _SwitchTaskJump
_SwitchTaskJump:
        pushl      %eax
        pushl      %ebx
        pushl      %ecx
        pushl      %edx
        pushl      %ebp
        pushl      %edi
        pushl      %esi
        movl       _Yield_esp,%eax
        movl       %esp,(%eax)
        movl       _Yield_vesp,%esp
        call       *_Yield_start
        call       _KillMyThread

------_=_NextPart_000_01C1A56C.7AB04D30--

- Raw text -


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