/*
 * switch.cxx
 *
 * Cooperative multi-threading stack switch function.
 *
 * Portable Windows Library
 *
 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is Portable Windows Library.
 *
 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
 *
 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
 * All Rights Reserved.
 *
 * Contributor(s): ______________________________________.
 *
 * $Log: switch.cxx,v $
 * Revision 1.23  2003/01/06 18:41:08  rogerh
 * Add NetBSD patches, taken from the NetBSD pkg patches.
 * Submitted by Andreas Wrede
 *
 * Revision 1.22  2002/10/10 04:43:44  robertj
 * VxWorks port, thanks Martijn Roest
 *
 * Revision 1.21  2001/08/11 15:38:43  rogerh
 * Add Mac OS Carbon changes from John Woods <jfw@jfwhome.funhouse.com>
 *
 * Revision 1.20  2000/03/08 12:17:09  rogerh
 * Add OpenBSD support
 *
 * Revision 1.19  1999/05/12 02:12:02  robertj
 * Fixed stack size on alpha
 *
 * Revision 1.18  1999/05/01 11:29:20  robertj
 * Alpha linux port changes.
 *
 * Revision 1.17  1999/03/05 07:03:27  robertj
 * Some more BeOS port changes.
 *
 * Revision 1.16  1999/02/22 13:26:54  robertj
 * BeOS port changes.
 *
 * Revision 1.15  1998/12/21 06:50:36  robertj
 * Linux PPC support
 *
 * Revision 1.14  1998/12/04 12:21:14  robertj
 * FreeBSD support
 *
 * Revision 1.13  1998/11/05 09:04:16  craigs
 * Changed free to runtime_free
 *
 * Revision 1.12  1998/09/24 04:12:21  robertj
 * Added open software license.
 *
 */

#include <ptlib.h>

#if !defined(P_PTHREADS) && !defined(BE_THREADS) && !defined(P_MAC_MPTHREADS) && !defined(VX_TASKS)

#ifdef P_LINUX
#ifdef PPC
#define	SET_STACK	context[0].__jmpbuf[0].__misc[0] = (long int)stackTop-16;
#define	STACK_MULT	4
#else
#ifdef JB_SP
#define	SET_STACK	context[0].__jmpbuf[JB_SP] = (INT)stackTop-16;
#else
#define	SET_STACK	context[0].__sp = (__ptr_t)stackTop-16;
#endif
#ifdef P_64BIT
#define STACK_MULT	5
#else
#include <sys/mman.h>
#define	USE_MMAP	MAP_ANON | MAP_PRIVATE
#endif
#endif
#endif

#if defined(P_FREEBSD) || defined(P_OPENBSD)  || defined(P_NETBSD)
#define	SET_STACK	context[0]._jb[2] = (int)stackTop-16;
#if defined(P_NETBSD)
#include <sys/mman.h>
#define        USE_MMAP        MAP_ANON | MAP_PRIVATE
#endif
#endif

#ifdef __BEOS__
#define	SET_STACK	context[0].__jmpbuf[JB_SP] = (int)stackTop-16;
#endif

#ifdef P_SUN4
#define	SETJMP_PROLOG	__asm__ ("ta 3"); 
#define SET_STACK	context[2] = ((int)stackTop-1024) & ~7;
#endif

#ifdef P_SOLARIS
#define	SETJMP_PROLOG	__asm__ ("ta 3"); 
#define SET_STACK	context[1] = ((int)stackTop-1024) & ~7;
#define	STACK_MULT	4
//#define	USE_MMAP	MAP_PRIVATE | MAP_NORESERVE
#include <sys/mman.h>
#endif

#ifdef P_HPUX
#define SET_STACK	context[1] = (int)(stackBase+64*2);
#endif

#ifdef P_ULTRIX
#define SET_STACK	context[JB_SP] = (int)(stackTop-16);
#endif

#ifndef	SETJMP_PROLOG
#define	SETJMP_PROLOG
#endif

#ifndef STACK_MIN
#define	STACK_MIN	10240
#endif

#ifndef	STACK_MULT
#define	STACK_MULT	1
#endif

static PThread * localThis;

void PThread::SwitchContext(PThread * from)
{
  //
  //  no need to switch to ourselves
  //
  if (this == from)
    return;

#ifdef SET_STACK

  //  save context for old thread
  SETJMP_PROLOG
  if (setjmp(from->context) != 0) // Are being reactivated from previous yield
    return;

  //  if starting the current thread, create a context, give it a new stack
  //  and then switch to it.
  //  if we have just switched into a new thread, execute the BeginThread
  //  function
  if (status == Starting) {
    localThis = this;
    SETJMP_PROLOG
    if (setjmp(context) != 0) { // Are being reactivated from previous yield
      localThis->BeginThread();
      PAssertAlways("Return from BeginThread not allowed");
    }
    SET_STACK
  }

  //  switch to the new thread
  longjmp(context, TRUE);
  PAssertAlways("Return from longjmp not allowed");

#else

#warning No lightweight thread context switch mechanism defined
  PAssertAlways("SwitchContext() not implemented");

#endif
}


void PThread::AllocateStack(PINDEX stackProtoSize)
{
  int stackSize = STACK_MULT*PMAX(STACK_MIN, stackProtoSize);

#if defined(USE_MMAP)
  stackBase = (char *)mmap(0,
                           stackSize,
                           PROT_READ | PROT_WRITE,
			   USE_MMAP,
                           -1, 0);
  PAssert(stackBase != (char *)-1, "Cannot allocate virtual stack for thread");
#else
  stackBase = (char *)malloc(stackSize);
  PAssert(stackBase != NULL, "Cannot allocate stack for thread");
#endif
  stackTop  = stackBase + stackSize-1;
}

void PThread::FreeStack()
{
  if (stackBase != NULL)
#if defined(USE_MMAP)
    munmap(stackBase, stackTop-stackBase+1);
#else
    free(stackBase);
#endif
}

#endif  // !P_PTHREADS && !BE_THREADS




syntax highlighted by Code2HTML, v. 0.9.1