Contiki 2.6

mtarch.c

00001 /*
00002  * Copyright (c) 2007, Swedish Institute of Computer Science.
00003  * All rights reserved. 
00004  *
00005  * Redistribution and use in source and binary forms, with or without 
00006  * modification, are permitted provided that the following conditions 
00007  * are met: 
00008  * 1. Redistributions of source code must retain the above copyright 
00009  *    notice, this list of conditions and the following disclaimer. 
00010  * 2. Redistributions in binary form must reproduce the above copyright 
00011  *    notice, this list of conditions and the following disclaimer in the 
00012  *    documentation and/or other materials provided with the distribution. 
00013  * 3. Neither the name of the Institute nor the names of its contributors 
00014  *    may be used to endorse or promote products derived from this software 
00015  *    without specific prior written permission. 
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
00027  * SUCH DAMAGE. 
00028  *
00029  * This file is part of the Contiki operating system.
00030  * 
00031  * Author: Oliver Schmidt <ol.sc@web.de>
00032  *
00033  * $Id: mtarch.c,v 1.2 2007/04/03 18:37:15 oliverschmidt Exp $
00034  */
00035 
00036 #if defined(_WIN32) || defined(__CYGWIN__)
00037 
00038 #define WIN32_LEAN_AND_MEAN
00039 #include <windows.h>
00040 
00041 static void *main_fiber;
00042 
00043 #elif defined(__linux) || defined(__APPLE__)
00044 
00045 #ifdef __APPLE__
00046 /* Avoid deprecated error on Darwin */
00047 #define _XOPEN_SOURCE
00048 #endif
00049 
00050 #include <stdlib.h>
00051 #include <signal.h>
00052 #include <ucontext.h>
00053 
00054 struct mtarch_t {
00055   char stack[4096];
00056   ucontext_t context;
00057 };
00058 
00059 static ucontext_t main_context;
00060 static ucontext_t *running_context;
00061 
00062 #endif /* _WIN32 || __CYGWIN__ || __linux */
00063 
00064 #include "mtarch.h"
00065 
00066 /*--------------------------------------------------------------------------*/
00067 void
00068 mtarch_init(void)
00069 {
00070 #if defined(_WIN32) || defined(__CYGWIN__)
00071 
00072   main_fiber = ConvertThreadToFiber(NULL);
00073 
00074 #endif /* _WIN32 || __CYGWIN__ */
00075 }
00076 /*--------------------------------------------------------------------------*/
00077 void
00078 mtarch_remove(void)
00079 {
00080 #if defined(_WIN32) || defined(__CYGWIN__)
00081 
00082   ConvertFiberToThread();
00083 
00084 #endif /* _WIN32 || __CYGWIN__ */
00085 }
00086 /*--------------------------------------------------------------------------*/
00087 void
00088 mtarch_start(struct mtarch_thread *thread,
00089              void (* function)(void *data),
00090              void *data)
00091 {
00092 #if defined(_WIN32) || defined(__CYGWIN__)
00093 
00094   thread->mt_thread = CreateFiber(0, (LPFIBER_START_ROUTINE)function, data);
00095 
00096 #elif defined(__linux)
00097 
00098   thread->mt_thread = malloc(sizeof(struct mtarch_t));
00099 
00100   getcontext(&((struct mtarch_t *)thread->mt_thread)->context);
00101 
00102   ((struct mtarch_t *)thread->mt_thread)->context.uc_link = NULL;
00103   ((struct mtarch_t *)thread->mt_thread)->context.uc_stack.ss_sp = 
00104                         ((struct mtarch_t *)thread->mt_thread)->stack;
00105   ((struct mtarch_t *)thread->mt_thread)->context.uc_stack.ss_size = 
00106                         sizeof(((struct mtarch_t *)thread->mt_thread)->stack);
00107 
00108   /* Some notes:
00109      - If a CPU needs stronger alignment for the stack than malloc()
00110        guarantees (like i.e. IA64) then makecontext() is supposed to
00111        add that alignment internally.
00112      - According to POSIX the arguments to function() are of type int
00113        and there are in fact 64-bit implementations which support only
00114        32 bits per argument meaning that a pointer argument has to be
00115        splitted into two arguments.
00116      - Most implementations interpret context.uc_stack.ss_sp on entry
00117        as the lowest stack address even if the CPU stack actually grows
00118        downwards. Although this means that ss_sp does NOT represent the
00119        CPU stack pointer this behaviour makes perfectly sense as it is
00120        the only way to stay independent from the CPU architecture. But
00121        Solaris prior to release 10 interprets ss_sp as highest stack
00122        address thus requiring special handling. */
00123   makecontext(&((struct mtarch_t *)thread->mt_thread)->context,
00124               (void (*)(void))function, 1, data);
00125 
00126 #endif /* _WIN32 || __CYGWIN__ || __linux */
00127 }
00128 /*--------------------------------------------------------------------------*/
00129 void
00130 mtarch_yield(void)
00131 {
00132 #if defined(_WIN32) || defined(__CYGWIN__)
00133 
00134   SwitchToFiber(main_fiber);
00135 
00136 #elif defined(__linux)
00137 
00138   swapcontext(running_context, &main_context);
00139 
00140 #endif /* _WIN32 || __CYGWIN__ || __linux */
00141 }
00142 /*--------------------------------------------------------------------------*/
00143 void
00144 mtarch_exec(struct mtarch_thread *thread)
00145 {
00146 #if defined(_WIN32) || defined(__CYGWIN__)
00147 
00148   SwitchToFiber(thread->mt_thread);
00149 
00150 #elif defined(__linux)
00151 
00152   running_context = &((struct mtarch_t *)thread->mt_thread)->context;
00153   swapcontext(&main_context, running_context);
00154   running_context = NULL;
00155 
00156 #endif /* _WIN32 || __CYGWIN__ || __linux */
00157 }
00158 /*--------------------------------------------------------------------------*/
00159 void
00160 mtarch_stop(struct mtarch_thread *thread)
00161 {
00162 #if defined(_WIN32) || defined(__CYGWIN__)
00163 
00164   DeleteFiber(thread->mt_thread);
00165 
00166 #elif defined(linux) || defined(__linux)
00167 
00168   free(thread->mt_thread);
00169 
00170 #endif /* _WIN32 || __CYGWIN__ || __linux */
00171 }
00172 /*--------------------------------------------------------------------------*/
00173 void
00174 mtarch_pstart(void)
00175 {
00176 }
00177 /*--------------------------------------------------------------------------*/
00178 void
00179 mtarch_pstop(void)
00180 {
00181 }
00182 /*--------------------------------------------------------------------------*/