Mail Archives: djgpp/2002/01/25/01:53:34
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>> I am currently trying to build a minimalistic multi-threaded kernel with</FONT>
<BR><FONT SIZE=2>> djgpp.</FONT>
<BR><FONT SIZE=2>> When I change stack selector (ss) my programs hangs when calling __dpmi_int</FONT>
<BR><FONT SIZE=2>> It **seems** that DJGPP assumes SS=DS in order to function correctly.</FONT>
<BR><FONT SIZE=2>> </FONT>
<BR><FONT SIZE=2>> 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>
</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 -