psthread.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 Ondrej Palkovsky
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  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00035 #include <libadt/list.h>
00036 #include <psthread.h>
00037 #include <malloc.h>
00038 #include <unistd.h>
00039 #include <thread.h>
00040 #include <stdio.h>
00041 #include <kernel/arch/faddr.h>
00042 #include <futex.h>
00043 #include <assert.h>
00044 #include <async.h>
00045 
00046 #ifndef PSTHREAD_INITIAL_STACK_PAGES_NO
00047 #define PSTHREAD_INITIAL_STACK_PAGES_NO 1
00048 #endif
00049 
00050 static LIST_INITIALIZE(ready_list);
00051 static LIST_INITIALIZE(serialized_list);
00052 static LIST_INITIALIZE(manager_list);
00053 
00054 static void psthread_main(void);
00055 
00056 static atomic_t psthread_futex = FUTEX_INITIALIZER;
00058 static int serialized_threads; /* Protected by async_futex */
00060 static __thread int serialization_count;
00062 static int threads_in_manager;
00063 
00065 psthread_data_t * psthread_setup()
00066 {
00067         psthread_data_t *pt;
00068         tcb_t *tcb;
00069 
00070         tcb = __make_tls();
00071         if (!tcb)
00072                 return NULL;
00073 
00074         pt = malloc(sizeof(*pt));
00075         if (!pt) {
00076                 __free_tls(tcb);
00077                 return NULL;
00078         }
00079 
00080         tcb->pst_data = pt;
00081         pt->tcb = tcb;
00082 
00083         return pt;
00084 }
00085 
00086 void psthread_teardown(psthread_data_t *pt)
00087 {
00088         __free_tls(pt->tcb);
00089         free(pt);
00090 }
00091 
00093 void psthread_main(void)
00094 {
00095         psthread_data_t *pt = __tcb_get()->pst_data;
00096 
00097         pt->retval = pt->func(pt->arg);
00098 
00099         pt->finished = 1;
00100         if (pt->waiter)
00101                 list_append(&pt->waiter->link, &ready_list);
00102 
00103         psthread_schedule_next_adv(PS_FROM_DEAD);
00104 }
00105 
00114 int psthread_schedule_next_adv(pschange_type ctype)
00115 {
00116         psthread_data_t *srcpt, *dstpt;
00117         int retval = 0;
00118         
00119         futex_down(&psthread_futex);
00120 
00121         if (ctype == PS_PREEMPT && list_empty(&ready_list))
00122                 goto ret_0;
00123 
00124         if (ctype == PS_FROM_MANAGER) {
00125                 if (list_empty(&ready_list) && list_empty(&serialized_list))
00126                         goto ret_0;
00127                 /* Do not preempt if there is not sufficient count of thread managers */
00128                 if (list_empty(&serialized_list) && threads_in_manager <= serialized_threads) {
00129                         goto ret_0;
00130                 }
00131         }
00132         /* If we are going to manager and none exists, create it */
00133         if (ctype == PS_TO_MANAGER || ctype == PS_FROM_DEAD) {
00134                 while (list_empty(&manager_list)) {
00135                         futex_up(&psthread_futex);
00136                         async_create_manager();
00137                         futex_down(&psthread_futex);
00138                 }
00139         }
00140         
00141         if (ctype != PS_FROM_DEAD) {
00142                 /* Save current state */
00143                 srcpt = __tcb_get()->pst_data;
00144                 if (!context_save(&srcpt->ctx)) {
00145                         if (serialization_count)
00146                                 srcpt->flags &= ~PSTHREAD_SERIALIZED;
00147                         return 1; // futex_up already done here
00148                 }
00149 
00150                 /* Save myself to correct run list */
00151                 if (ctype == PS_PREEMPT)
00152                         list_append(&srcpt->link, &ready_list);
00153                 else if (ctype == PS_FROM_MANAGER) {
00154                         list_append(&srcpt->link, &manager_list);
00155                         threads_in_manager--;
00156                 } /* If ctype == PS_TO_MANAGER, don't save ourselves to any list, we should
00157                    * already be somewhere, or we will be lost */
00158         } else
00159                 srcpt = NULL; /* Avoid GCC warning, if ctype == PS_FROM_DEAD, srcpt is not used */
00160 
00161         /* Choose new thread to run */
00162         if (ctype == PS_TO_MANAGER || ctype == PS_FROM_DEAD) {
00163                 dstpt = list_get_instance(manager_list.next,psthread_data_t, link);
00164                 if (serialization_count && ctype == PS_TO_MANAGER) {
00165                         serialized_threads++;
00166                         srcpt->flags |= PSTHREAD_SERIALIZED;
00167                 }
00168                 threads_in_manager++;
00169         } else {
00170                 if (!list_empty(&serialized_list)) {
00171                         dstpt = list_get_instance(serialized_list.next, psthread_data_t, link);
00172                         serialized_threads--;
00173                 } else
00174                         dstpt = list_get_instance(ready_list.next, psthread_data_t, link);
00175         }
00176         list_remove(&dstpt->link);
00177 
00178         futex_up(&psthread_futex);
00179         context_restore(&dstpt->ctx);
00180 
00181 ret_0:
00182         futex_up(&psthread_futex);
00183         return retval;
00184 }
00185 
00192 int psthread_join(pstid_t psthrid)
00193 {
00194         volatile psthread_data_t *pt;
00195         volatile int retval;
00196 
00197         /* Handle psthrid = Kernel address -> it is wait for call */
00198         pt = (psthread_data_t *) psthrid;
00199 
00200         /* TODO */
00201         printf("join unsupported\n");
00202         _exit(1);
00203 
00204         retval = pt->retval;
00205 
00206         free(pt->stack);
00207         psthread_teardown((void *)pt);
00208 
00209         return retval;
00210 }
00211 
00220 pstid_t psthread_create(int (*func)(void *), void *arg)
00221 {
00222         psthread_data_t *pt;
00223 
00224         pt = psthread_setup();
00225         if (!pt) 
00226                 return 0;
00227         pt->stack = (char *) malloc(PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize());
00228 
00229         if (!pt->stack) {
00230                 psthread_teardown(pt);
00231                 return 0;
00232         }
00233 
00234         pt->arg= arg;
00235         pt->func = func;
00236         pt->finished = 0;
00237         pt->waiter = NULL;
00238         pt->flags = 0;
00239 
00240         context_save(&pt->ctx);
00241         context_set(&pt->ctx, FADDR(psthread_main), pt->stack, PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize(), pt->tcb);
00242 
00243         return (pstid_t )pt;
00244 }
00245 
00247 void psthread_add_ready(pstid_t psthrid)
00248 {
00249         psthread_data_t *pt;
00250 
00251         pt = (psthread_data_t *) psthrid;
00252         futex_down(&psthread_futex);
00253         if ((pt->flags & PSTHREAD_SERIALIZED))
00254                 list_append(&pt->link, &serialized_list);
00255         else
00256                 list_append(&pt->link, &ready_list);
00257         futex_up(&psthread_futex);
00258 }
00259 
00261 void psthread_add_manager(pstid_t psthrid)
00262 {
00263         psthread_data_t *pt;
00264 
00265         pt = (psthread_data_t *) psthrid;
00266 
00267         futex_down(&psthread_futex);
00268         list_append(&pt->link, &manager_list);
00269         futex_up(&psthread_futex);
00270 }
00271 
00273 void psthread_remove_manager()
00274 {
00275         futex_down(&psthread_futex);
00276         if (list_empty(&manager_list)) {
00277                 futex_up(&psthread_futex);
00278                 return;
00279         }
00280         list_remove(manager_list.next);
00281         futex_up(&psthread_futex);
00282 }
00283 
00285 pstid_t psthread_get_id(void)
00286 {
00287         return (pstid_t)__tcb_get()->pst_data;
00288 }
00289 
00298 void psthread_inc_sercount(void)
00299 {
00300         serialization_count++;
00301 }
00302 
00303 void psthread_dec_sercount(void)
00304 {
00305         serialization_count--;
00306 }
00307 
00308 

Generated on Sun Jun 18 18:00:18 2006 for HelenOS Userspace (ia64) by  doxygen 1.4.6