scheduling for ppc
Josh DuBois
duboisj at codeweavers.com
Sat Mar 10 16:56:15 CST 2001
Hi -
These two patches make the scheduler work on PPC.
ChangeLog:
scheduler/sysdeps.c
provide thread switching for PPC
scheduler/critsection.c
provide Interlocked* functions for ppc
include/thread.h
add a field for unix thread ID to TEB block.
--
Josh DuBois
654 SW Grant #103, Portland, OR 97201
(503)-827-4818
duboisj at codeweavers.com
-------------- next part --------------
Index: include/thread.h
===================================================================
RCS file: /home/cvs/wine/wine/include/thread.h,v
retrieving revision 1.50
diff -u -r1.50 thread.h
--- include/thread.h 2001/03/08 01:16:41 1.50
+++ include/thread.h 2001/03/10 22:13:54
@@ -100,10 +100,13 @@
int wait_fd[2]; /* --3 214 fd for sleeping server requests */
void *debug_info; /* --3 21c Info for debugstr functions */
void *pthread_data; /* --3 220 Data for pthread emulation */
+
+ int utid; /* --3 224 Unix Thread ID */
+
/* here is plenty space for wine specific fields (don't forget to change pad6!!) */
/* the following are nt specific fields */
- DWORD pad6[629]; /* --n 224 */
+ DWORD pad6[628]; /* --n 228 */
UNICODE_STRING StaticUnicodeString; /* -2- bf8 used by advapi32 */
USHORT StaticUnicodeBuffer[261]; /* -2- c00 used by advapi32 */
DWORD pad7; /* --n e0c */
-------------- next part --------------
Index: scheduler/critsection.c
===================================================================
RCS file: /home/cvs/wine/wine/scheduler/critsection.c,v
retrieving revision 1.25
diff -u -r1.25 critsection.c
--- scheduler/critsection.c 2000/11/25 01:31:18 1.25
+++ scheduler/critsection.c 2001/03/10 22:15:16
@@ -226,6 +226,121 @@
return retv;
}
+#elif defined (__PPC__)
+
+PVOID WINAPI InterlockedCompareExchange( PVOID *dest, PVOID xchg, PVOID compare )
+{
+ int ret;
+ int scratch;
+
+ __asm__ __volatile__(
+ "sync; "
+ "0: lwarx %0,0,%2 ;"
+ " xor. %1,%4,%0;"
+ " bne 1f;"
+ " stwcx. %3,0,%2;"
+ " bne- 0b;"
+ "1: "
+ "sync; "
+ : "=&r"(ret), "=&r"(scratch)
+ : "r"(dest), "r"(xchg), "r"(compare)
+ : "cr0", "memory");
+
+ return (PVOID)ret;
+}
+
+/***********************************************************************
+ * InterlockedExchange (KERNEL32.@)
+ */
+LONG WINAPI InterlockedExchange( PLONG dest, LONG val )
+{
+ void *ret __attribute__ ((aligned (4))) = &ret;
+ int zero = 0;
+
+ __asm__ __volatile__(
+ "sync; "
+ "0: lwarx %0,0,%1 ;"
+ " stwcx. %2,0,%1;"
+ " bne- 0b;"
+ "sync; "
+ : "=&r"(ret)
+ : "r"(dest), "r"(val)
+ : "cr0", "memory");
+
+
+ return ret;
+}
+
+/***********************************************************************
+ * InterlockedExchangeAdd (KERNEL32.@)
+ */
+LONG WINAPI InterlockedExchangeAdd( PLONG dest, LONG incr )
+{
+ void *ret __attribute__ ((aligned (4))) = &ret;
+ int inc = incr;
+ int zero = 0;
+
+ __asm__ __volatile__(
+ "sync; "
+ "0: lwarx %0, %3, %1;"
+ " add %0, %2, %0;"
+ " stwcx. %0, %3, %1;"
+ " bne- 0b;"
+ "sync; "
+ : "=&r"(ret)
+ : "r"(dest), "r"(inc), "r"(zero)
+ : "cr0", "memory");
+
+ return (LONG)ret;
+}
+
+/***********************************************************************
+ * InterlockedIncrement (KERNEL32.@)
+ */
+LONG WINAPI InterlockedIncrement( PLONG dest )
+{
+ void *ret __attribute__ ((aligned (4))) = &ret;
+ int inc = 1;
+ int zero = 0;
+
+ __asm__ __volatile__(
+ "sync; "
+ "0: lwarx %0, %3, %1;"
+ " add %0, %2, %0;"
+ " stwcx. %0, %3, %1;"
+ " bne- 0b;"
+ "sync; "
+ : "=&r"(ret)
+ : "r"(dest), "r"(inc), "r"(zero)
+ : "cr0", "memory");
+
+ return (LONG)ret;
+}
+
+/***********************************************************************
+ * InterlockedDecrement (KERNEL32.@)
+ */
+LONG WINAPI InterlockedDecrement( PLONG dest )
+{
+ void *ret __attribute__ ((aligned (4))) = &ret;
+ int inc = 1;
+ int zero = 0;
+
+ __asm__ __volatile__(
+ "sync; "
+ "0: lwarx %0, %3, %1;"
+ " subf %0, %2, %0;"
+ " stwcx. %0, %3 ,%1;"
+ " bne- 0b;"
+ "sync; "
+ : "=&r"(ret)
+ : "r"(dest), "r"(inc), "r"(zero)
+ : "cr0", "memory");
+
+ return (LONG)ret;
+}
+
+
#else
#error You must implement the Interlocked* functions for your CPU
#endif
Index: scheduler/sysdeps.c
===================================================================
RCS file: /home/cvs/wine/wine/scheduler/sysdeps.c,v
retrieving revision 1.33
diff -u -r1.33 sysdeps.c
--- scheduler/sysdeps.c 2001/03/01 22:13:49 1.33
+++ scheduler/sysdeps.c 2001/03/10 22:15:16
@@ -20,6 +20,7 @@
#ifdef HAVE_UCONTEXT_H
# include <ucontext.h>
#endif
+#include <assert.h>
#include "wine/port.h"
#include "thread.h"
#include "server.h"
@@ -40,8 +41,24 @@
# define CLONE_SIGHAND 0x00000800
# define CLONE_PID 0x00001000
# endif /* CLONE_VM */
+
+#ifdef __PPC__
+#define USE_GENERIC_LINUX_THREADING
+#endif
+
#endif /* linux */
+#ifdef USE_GENERIC_LINUX_THREADING
+
+#include <linux/tasks.h>
+
+void GLT_RemoveCurrentTEB();
+void GLT_LockTEBList();
+void GLT_UnlockTEBList();
+int GLT_TEBListLock = 0;
+static TEB* GLT_TEBList[MAX_TASKS_PER_USER];
+#endif
+
/***********************************************************************
* SYSDEPS_SetCurThread
*
@@ -55,6 +72,47 @@
#elif defined(HAVE__LWP_CREATE)
/* On non-i386 Solaris, we use the LWP private pointer */
_lwp_setprivate( teb );
+#elif defined(USE_GENERIC_LINUX_THREADING)
+
+ int j;
+ int found = 0;
+
+ GLT_LockTEBList();
+
+ for(j = 0; j < MAX_TASKS_PER_USER; j++)
+ {
+ if(GLT_TEBList[j] == teb)
+ {
+ found = 1;
+ break;
+ }
+ }
+
+ /* -----------------------------------------------------------
+ ** If the TEB isn't in the list already, we have to insert it.
+ ** ----------------------------------------------------------- */
+ if(!found)
+ {
+ for(j = 0; j < MAX_TASKS_PER_USER; j++)
+ {
+ if(!GLT_TEBList[j])
+ {
+ GLT_TEBList[j] = teb;
+
+ /* -----------------------------------------------
+ ** Record the pid so we can find this TEB
+ ** later on.
+ ** ----------------------------------------------- */
+ teb->utid = getpid();
+ break;
+ }
+ }
+ }
+
+ GLT_UnlockTEBList();
+
+#else
+#error "SYSDEPS_SetCurThread isn't defined for this platform."
#endif
}
@@ -148,7 +206,13 @@
{
int fd = NtCurrentTeb()->request_fd;
NtCurrentTeb()->request_fd = -1;
+
+#ifdef USE_GENERIC_LINUX_THREADING
+ GLT_RemoveCurrentTEB();
+#endif
+
close( fd );
+
#ifdef HAVE__LWP_CREATE
_lwp_exit();
#endif
@@ -202,12 +266,29 @@
".byte 0x64; popl 0x04\n\t"
"popl %ebp\n\t"
"ret" );
-#else
+#elif defined(__PPC__)
+int SYSDEPS_CallOnStack( LPVOID stackTop, LPVOID stackLow,
+ int (*func)(LPVOID), LPVOID arg )
+{
+ TEB *curTeb = NtCurrentTeb();
+
+ curTeb->stack_top = stackTop;
+ curTeb->stack_low = stackLow;
+
+ __asm__ __volatile__("mr 1, %0"
+ :
+ : "r"(stackTop) );
+
+ return SYSDEPS_DoCallOnStack( func, arg );
+}
+#elif defined (__sparc__)
int SYSDEPS_CallOnStack( LPVOID stackTop, LPVOID stackLow,
int (*func)(LPVOID), LPVOID arg )
{
return SYSDEPS_DoCallOnStack( func, arg );
}
+#else
+#error "You need to define stack-switching code for your architecture."
#endif
/***********************************************************************
@@ -250,6 +331,92 @@
extern void *_lwp_getprivate(void);
return (struct _TEB *)_lwp_getprivate();
}
+
+#elif defined(USE_GENERIC_LINUX_THREADING)
+
+struct _TEB * WINAPI NtCurrentTeb(void)
+{
+ TEB *teb = NULL;
+ int pid = getpid();
+ int j;
+
+ GLT_LockTEBList();
+
+ for(j = 0; j < MAX_TASKS_PER_USER; j++)
+ {
+ if(GLT_TEBList[j] != NULL)
+ {
+ if(GLT_TEBList[j]->utid == pid)
+ {
+ teb = GLT_TEBList[j];
+ break;
+ }
+ }
+ }
+
+ GLT_UnlockTEBList();
+
+ assert(teb);
+ return teb;
+}
#else
# error NtCurrentTeb not defined for this architecture
#endif /* __i386__ */
+
+#ifdef USE_GENERIC_LINUX_THREADING
+
+/* ---------------------------------------------------------------
+** GLT_RemoveCurrentTEB()
+** remove the current TEB from the teb list
+** --------------------------------------------------------------- */
+void GLT_RemoveCurrentTEB()
+{
+ TEB *teb = NtCurrentTeb();
+ int j;
+
+ GLT_LockTEBList();
+
+ for(j = 0; j < MAX_TASKS_PER_USER; j++)
+ {
+ if(GLT_TEBList[j] == teb)
+ {
+ GLT_TEBList[j] = NULL;
+ break;
+ }
+ }
+
+ GLT_UnlockTEBList();
+}
+
+void GLT_LockTEBList()
+{
+ int oldVal;
+ int pid = getpid();
+
+ do
+ {
+ oldVal = (int)InterlockedCompareExchange((void*)&GLT_TEBListLock,
+ (void*)pid,
+ (void*)0);
+ } while(oldVal != 0);
+
+ return;
+}
+
+void GLT_UnlockTEBList()
+{
+ int oldVal;
+ int pid = getpid();
+
+ oldVal = (int)InterlockedCompareExchange((void *)&GLT_TEBListLock,
+ (void*)0,
+ (void*)pid);
+ if(oldVal != pid)
+ {
+ _exit(-1);
+ }
+
+ return;
+}
+
+#endif /* USE_GENERIC_LINUX_THREADING */
More information about the wine-patches
mailing list