sthread_core_pthread.cpp

00001 /* -*- mode:C++; c-basic-offset:4 -*-
00002      Shore-MT -- Multi-threaded port of the SHORE storage manager
00003    
00004                        Copyright (c) 2007-2009
00005       Data Intensive Applications and Systems Labaratory (DIAS)
00006                Ecole Polytechnique Federale de Lausanne
00007    
00008                          All Rights Reserved.
00009    
00010    Permission to use, copy, modify and distribute this software and
00011    its documentation is hereby granted, provided that both the
00012    copyright notice and this permission notice appear in all copies of
00013    the software, derivative works or modified versions, and any
00014    portions thereof, and that both notices appear in supporting
00015    documentation.
00016    
00017    This code is distributed in the hope that it will be useful, but
00018    WITHOUT ANY WARRANTY; without even the implied warranty of
00019    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS
00020    DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
00021    RESULTING FROM THE USE OF THIS SOFTWARE.
00022 */
00023 
00024 /*<std-header orig-src='shore'>
00025 
00026  $Id: sthread_core_pthread.cpp,v 1.8 2010/06/08 22:28:00 nhall Exp $
00027 
00028 SHORE -- Scalable Heterogeneous Object REpository
00029 
00030 Copyright (c) 1994-99 Computer Sciences Department, University of
00031                       Wisconsin -- Madison
00032 All Rights Reserved.
00033 
00034 Permission to use, copy, modify and distribute this software and its
00035 documentation is hereby granted, provided that both the copyright
00036 notice and this permission notice appear in all copies of the
00037 software, derivative works or modified versions, and any portions
00038 thereof, and that both notices appear in supporting documentation.
00039 
00040 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY
00041 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS
00042 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND
00043 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
00044 
00045 This software was developed with support by the Advanced Research
00046 Project Agency, ARPA order number 018 (formerly 8230), monitored by
00047 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518.
00048 Further funding for this work was provided by DARPA through
00049 Rome Research Laboratory Contract No. F30602-97-2-0247.
00050 
00051 */
00052 
00053 #include "w_defines.h"
00054 
00055 /*  -- do not edit anything above this line --   </std-header>*/
00056 
00057 
00058 /*
00059  *   NewThreads is Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998 by:
00060  *
00061  *    Josef Burger    <bolo@cs.wisc.edu>
00062  *    Dylan McNamee    <dylan@cse.ogi.edu>
00063  *      Ed Felten       <felten@cs.princeton.edu>
00064  *
00065  *   All Rights Reserved.
00066  *
00067  *   NewThreads may be freely used as long as credit is given
00068  *   to the above authors and the above copyright is maintained.
00069  */
00070 
00071 #include <w.h>
00072 #include "sthread.h"
00073 #include <w_stream.h>
00074 #include <pthread.h>
00075 #include "stcore_pthread.h"
00076 
00077 
00078 
00079 #define    USER_STACK_SIZE        (sthread_t::default_stack)
00080 #define    DEFAULT_STACK_SIZE    (USER_STACK_SIZE)
00081 
00082 
00083 #ifndef HAVE_SEMAPHORE_H
00084 // TODO: move this to another file or get rid of it altogether
00085 /* Mimic the posix semaphores so it just works.  They release
00086    waiters when the count is > 0, sleep if <= 0 */
00087 
00088 static    int    sem_init(sthread_core_t::sem_t *sem, int, int count)
00089 {
00090     /* XXX could bitch if shared was true, but it is just for
00091        local compatability */
00092 
00093     sem->count = count;
00094     DO_PTHREAD(pthread_mutex_init(&sem->lock, NULL));
00095     DO_PTHREAD(pthread_cond_init(&sem->wake, NULL));
00096 
00097     return 0;
00098 }
00099 
00100 static    void    sem_destroy(sthread_core_t::sem_t *sem)
00101 {
00102     DO_PTHREAD(pthread_mutex_destroy(&sem->lock));
00103     DO_PTHREAD(pthread_cond_destroy(&sem->wake));
00104 }
00105 
00106 static    inline    void    sem_post(sthread_core_t::sem_t *sem)
00107 {
00108     DO_PTHREAD(pthread_mutex_lock(&sem->lock));
00109     sem->count++;
00110     if (sem->count > 0)
00111         DO_PTHREAD(pthread_cond_signal(&sem->wake));
00112     DO_PTHREAD(pthread_mutex_unlock(&sem->lock));
00113 }
00114 
00115 static    inline    void    sem_wait(sthread_core_t::sem_t *sem)
00116 {
00117     DO_PTHREAD(pthread_mutex_lock(&sem->lock));
00118     while (sem->count <= 0)
00119         DO_PTHREAD(pthread_cond_wait(&sem->wake, &sem->lock));
00120     sem->count--;
00121     DO_PTHREAD(pthread_mutex_unlock(&sem->lock));
00122 }
00123 #endif
00124 
00125 
00126 // starting function called by every pthread created; core* is the
00127 // argument. Through the core* we get the "real function and arg.
00128 extern "C" void *pthread_core_start(void *_arg);
00129 void *pthread_core_start(void *_arg)
00130 {
00131     sthread_core_t    *me = (sthread_core_t *) _arg;
00132 
00133     // core is_virgin says the "real" function hasn't started yet
00134     // Unfortunately, we have multiple phases of startup here
00135     me->is_virgin = 0;
00136     (me->start_proc)(me->start_arg);
00137     return 0;
00138 }
00139 
00140 
00141 int sthread_core_init(sthread_core_t *core,
00142               void (*proc)(void *), void *arg,
00143               unsigned stack_size)
00144 {
00145     int    n;
00146 
00147     /* Get a life; XXX magic number */
00148     if (stack_size > 0 && stack_size < 1024)
00149         return -1;
00150 
00151     core->is_virgin = 1;
00152     core->start_proc = proc;
00153     core->start_arg = arg;
00154     core->stack_size = stack_size;
00155 
00156     if (stack_size > 0) {
00157         /* A real thread :thread id, default attributes, start func, arg */
00158         n = pthread_create(&core->pthread, NULL, pthread_core_start, core);
00159         if (n == -1) {
00160             w_rc_t e= RC(fcOS);
00161             // EAGAIN: insufficient resources
00162             // Really, there's no way to tell when the system will
00163             // say it's hit the maximum # threads because that depends
00164             // on a variety of resources, and in any case, we don't
00165             // know how much memory will be required for another thread.
00166             cerr << "pthread_create():" << endl << e << endl;
00167             return -1;
00168         }
00169         core->creator = pthread_self();
00170     }
00171     else {
00172         /* This is the main thread.  It runs in the "system"
00173            pthread; no pthread_create is needed.
00174          */
00175 
00176         /* A more elegant solution would be to make a
00177            "fake" stack using the kernel stack origin
00178            and stacksize limit.   This could also allow
00179            the main() stack to have a thread-package size limit,
00180            to catch memory hogs in the main thread. */
00181 
00182         /* The system stack is never virgin */
00183         core->is_virgin = 0;
00184         core->pthread = pthread_self();
00185         core->creator = core->pthread; // main thread
00186     }
00187     return 0;
00188 }
00189 
00190 /* clean up : called on destruction.
00191  * All we do now is join the thread
00192  */
00193 void sthread_core_exit(sthread_core_t* core, bool &joined)
00194 {
00195     void    *join_value=NULL;
00196     if(joined) {
00197         return;
00198     }
00199 
00200     /* must wait for the thread and then harvest its thread */
00201 
00202     if (core->stack_size > 0) {
00203         int res = pthread_join(core->pthread, &join_value);
00204         if(res) {
00205             const char *msg="";
00206             switch(res) {
00207                 case EINVAL:
00208                     msg = "Not a joinable thread: EINVAL";
00209                     break;
00210                 case ESRCH:
00211                     msg = "No such thread: ESRCH";
00212                     break;
00213                 case EDEADLK:
00214                     msg = "Joining with self: EDEADLK";
00215                     break;
00216                 default:
00217                     break;
00218             }
00219             if(res) {
00220                w_ostrstream o;
00221                o << "sthread_core_exit:"
00222                    << " Unexpected result from pthread_join: "
00223                    << msg << " core is : ";
00224 
00225                o << *core << endl;
00226 
00227                W_FATAL_MSG(fcINTERNAL,  << o.c_str() << endl);
00228             }
00229         }
00230         /* And the thread is gone */
00231     }
00232     joined = true;
00233 }
00234 
00235 ostream &operator<<(ostream &o, const sthread_core_t &core)
00236 {
00237     o << "core: ";
00238     if (core.stack_size == 0)
00239         W_FORM(o)("[ system thread %#lx creator %#lx ]", 
00240                 (long) core.pthread, 
00241                 (long) core.creator
00242                 );
00243     else
00244         W_FORM(o)("[ thread %#lx creator %#lx ] size=%d",  
00245             (long) core.pthread, 
00246             (long) core.creator, 
00247             core.stack_size);
00248     if (core.is_virgin)
00249         o << ", virgin-core";
00250     return o;
00251 }

Generated on Wed Jul 7 17:22:32 2010 for Shore Storage Manager by  doxygen 1.4.7