thread.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2000-2004 by ETH Zurich
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
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 copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY ETH ZURICH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ETH ZURICH
00021  *  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00034 /* 
00035  * unix_thread.c - unix emulation of cooperative threads using pthreads
00036  *
00037  * 2004.04.01 Matthias Ringwald <matthias.ringwald@inf.ethz.ch>
00038  *
00039  */
00040 
00041 #include <cfg/os.h>
00042 #include <pthread.h>
00043 #include <stdio.h>
00044 
00045 // #include <cfg/memory.h>
00046 
00047 #include <string.h>
00048 
00049 #include <sys/types.h>
00050 #include <sys/heap.h>
00051 #include <sys/atom.h>
00052 // #include <sys/timer.h>
00053 #include <sys/thread.h>
00054 
00055 #ifdef NUTDEBUG
00056 #include <sys/osdebug.h>
00057 #endif
00058 
00059 
00064 
00065 /* reused parameters for other calls */
00066 pthread_attr_t attr;
00067 
00068 /* protect thread signaling */
00069 pthread_mutex_t thread_mutex;
00070 
00071 /* to get a new thread start acked'd */
00072 pthread_cond_t main_cv;
00073 
00074 /* level of critical sections entered but not left outside a thread */
00075 uint16_t main_cs_level;
00076 
00077 /* has to be initialized once */
00078 void NutThreadInit()
00079 {
00080     /* Initialize mutex and condition variable objects */
00081     pthread_mutex_init(&thread_mutex, NULL);
00082 
00083     pthread_attr_init(&attr);
00084     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
00085 
00086     // main_cv init
00087     pthread_cond_init(&main_cv, NULL);
00088 }
00089 
00090 
00091 /*
00092  * This code is executed when entering a thread.
00093  *  
00094  *
00095  */
00096 static void *NutThreadEntry(void *arg);
00097 static void *NutThreadEntry(void *arg)
00098 {
00099     // get THREADINFO back
00100     NUTTHREADINFO *td = (NUTTHREADINFO *) arg;
00101 
00102     // confirm start
00103     pthread_mutex_lock(&thread_mutex);
00104     pthread_cond_signal(&main_cv);
00105 
00106     // wait for start signaled
00107     pthread_cond_wait(&td->td_cv, &thread_mutex);
00108     pthread_mutex_unlock(&thread_mutex);
00109 
00110     // set critical section value 
00111     td->td_cs_level = 0;
00112 
00113     // enable interrupts
00114     pthread_sigmask(SIG_UNBLOCK, &irq_signal, 0);
00115 
00116     // call real function
00117     td->td_fn(td->td_arg);
00118 
00119     // NutExitCritical();
00120 
00121     // tell nut/os about it
00122     NutThreadExit();
00123 
00124     // thread exit routine 
00125     pthread_exit(NULL);
00126 
00127     // make some compilers happy
00128     return NULL;
00129 }
00130 
00143 void NutThreadSwitch(void);
00144 void NutThreadSwitch(void)
00145 {
00146     NUTTHREADINFO *myself;
00147 
00148     NutEnterCritical();
00149 
00150     // lock thread switching mutex
00151     pthread_mutex_lock(&thread_mutex);
00152 
00153     // next thread is the first one in the run queue
00154     myself = runningThread;
00155     if (runningThread != runQueue) {
00156 
00157         // switching call
00158         runningThread = runQueue;
00159         runningThread->td_state = TDS_RUNNING;
00160 
00161         pthread_cond_signal(&runQueue->td_cv);
00162         pthread_cond_wait(&myself->td_cv, &thread_mutex);
00163 
00164     }
00165     pthread_mutex_unlock(&thread_mutex);
00166 
00167     NutExitCritical();
00168 }
00169 
00170 
00171 
00172 
00191 HANDLE NutThreadCreate(char * name, void (*fn) (void *), void *arg, size_t stackSize)
00192 {
00193     NUTTHREADINFO *td;
00194     const uintptr_t *paddr;
00195 
00196     paddr = (const uintptr_t *) fn;
00197 
00198     NutEnterCritical();
00199 
00200     /*
00201      * Allocate stack and thread info structure in one block.
00202      */
00203     if ((td = NutHeapAlloc(sizeof(NUTTHREADINFO))) == 0) {
00204         NutExitCritical();
00205         return 0;
00206     }
00207 
00208     /* store thread name */
00209     memcpy(td->td_name, name, sizeof(td->td_name) - 1);
00210     td->td_name[sizeof(td->td_name) - 1] = 0;
00211 
00212     // set initial critical section value 
00213     td->td_cs_level = 1;
00214 
00215     /*
00216      * Insert into the thread list and the run queue.
00217      */
00218     td->td_priority = 64;
00219     td->td_next = nutThreadList;
00220     nutThreadList = td;
00221     td->td_state = TDS_READY;
00222     td->td_timer = 0;
00223     td->td_queue = 0;
00224 #ifdef NUTDEBUG
00225     if (__os_trf) {
00226         fprintf(__os_trs, "Cre<%08lx>\n", (uintptr_t) td);
00227     }
00228 #endif
00229     NutThreadAddPriQueue(td, (NUTTHREADINFO **) & runQueue);
00230 #ifdef NUTDEBUG
00231     if (__os_trf)
00232         NutDumpThreadList(__os_trs);
00233 #endif
00234 
00235     // init thread structure
00236     pthread_cond_init(&td->td_cv, NULL);
00237 
00238     td->td_fn = fn;
00239     td->td_arg = arg;
00240 
00241     /*
00242      * If no thread is active, switch to new thread.
00243      * this also means, we're called from nutinit
00244      * (if not, there would be a runningThread..)
00245      *  
00246      */
00247     if (runningThread == 0) {
00248 
00249         // correct cs level counter
00250         // main_cs_level--;
00251         NutExitCritical();
00252 
00253         // switching
00254         runningThread = runQueue;
00255         runningThread->td_state = TDS_RUNNING;
00256 
00257         // set initial critical section value and enable interrupts
00258         runningThread->td_cs_level = 0;
00259         pthread_sigmask(SIG_UNBLOCK, &irq_signal, 0);
00260 
00261         // go!
00262         fn(arg);
00263 
00264         printf("Nut/OS Application terminated.\n\r");
00265         exit(0);
00266     };
00267 
00268     // lock mutex and start thread
00269     pthread_mutex_lock(&thread_mutex);
00270     pthread_create(&td->td_pthread, &attr, NutThreadEntry, (void *) td);
00271 
00272     // wait for ack
00273     pthread_cond_wait(&main_cv, &thread_mutex);
00274     pthread_mutex_unlock(&thread_mutex);
00275 
00276     /*
00277      * If current context is not in front of
00278      * the run queue (highest priority), then
00279      * switch to the thread in front.
00280      */
00281     if (runningThread != runQueue) {
00282         runningThread->td_state = TDS_READY;
00283 #ifdef NUTDEBUG
00284         if (__os_trf)
00285             fprintf(__os_trs, "New<%08lx %08lx>\n", (uintptr_t) runningThread, (uintptr_t) runQueue);
00286 #endif
00287         NutThreadSwitch();
00288     }
00289     NutExitCritical();
00290 
00291     return td;
00292 }
00293 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/