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.10 2010/12/09 15:20:17 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 <w_pthread.h>
00075 #include "stcore_pthread.h"
00076 
00077 #ifndef HAVE_SEMAPHORE_H
00078 // TODO: move this to another file or get rid of it altogether
00079 /* Mimic the posix semaphores so it just works.  They release
00080    waiters when the count is > 0, sleep if <= 0 */
00081 
00082 static    int    sem_init(sthread_core_t::sem_t *sem, int, int count)
00083 {
00084     /* XXX could bitch if shared was true, but it is just for
00085        local compatability */
00086 
00087     sem->count = count;
00088     DO_PTHREAD(pthread_mutex_init(&sem->lock, NULL));
00089     DO_PTHREAD(pthread_cond_init(&sem->wake, NULL));
00090 
00091     return 0;
00092 }
00093 
00094 static    void    sem_destroy(sthread_core_t::sem_t *sem)
00095 {
00096     DO_PTHREAD(pthread_mutex_destroy(&sem->lock));
00097     DO_PTHREAD(pthread_cond_destroy(&sem->wake));
00098 }
00099 
00100 static    inline    void    sem_post(sthread_core_t::sem_t *sem)
00101 {
00102     DO_PTHREAD(pthread_mutex_lock(&sem->lock));
00103     sem->count++;
00104     if (sem->count > 0)
00105         DO_PTHREAD(pthread_cond_signal(&sem->wake));
00106     DO_PTHREAD(pthread_mutex_unlock(&sem->lock));
00107 }
00108 
00109 static    inline    void    sem_wait(sthread_core_t::sem_t *sem)
00110 {
00111     DO_PTHREAD(pthread_mutex_lock(&sem->lock));
00112     while (sem->count <= 0)
00113         DO_PTHREAD(pthread_cond_wait(&sem->wake, &sem->lock));
00114     sem->count--;
00115     DO_PTHREAD(pthread_mutex_unlock(&sem->lock));
00116 }
00117 #endif
00118 
00119 
00120 // starting function called by every pthread created; core* is the
00121 // argument. Through the core* we get the "real function and arg.
00122 extern "C" void *pthread_core_start(void *_arg);
00123 void *pthread_core_start(void *_arg)
00124 {
00125     sthread_core_t    *me = (sthread_core_t *) _arg;
00126 
00127     // core is_virgin says the "real" function hasn't started yet
00128     // Unfortunately, we have multiple phases of startup here
00129     me->is_virgin = 0;
00130     (me->start_proc)(me->start_arg);
00131     return 0;
00132 }
00133 
00134 
00135 int sthread_core_init(sthread_core_t *core,
00136               void (*proc)(void *), void *arg,
00137               unsigned stack_size)
00138 {
00139     int    n;
00140 
00141     /* Get a life; XXX magic number */
00142     if (stack_size > 0 && stack_size < 1024)
00143         return -1;
00144 
00145     core->is_virgin = 1;
00146     core->start_proc = proc;
00147     core->start_arg = arg;
00148     core->stack_size = stack_size;
00149 
00150     if (stack_size > 0) {
00151         /* A real thread :thread id, default attributes, start func, arg */
00152         n = pthread_create(&core->pthread, NULL, pthread_core_start, core);
00153         if (n == -1) {
00154             w_rc_t e= RC(fcOS);
00155             // EAGAIN: insufficient resources
00156             // Really, there's no way to tell when the system will
00157             // say it's hit the maximum # threads because that depends
00158             // on a variety of resources, and in any case, we don't
00159             // know how much memory will be required for another thread.
00160             cerr << "pthread_create():" << endl << e << endl;
00161             return -1;
00162         }
00163         core->creator = pthread_self();
00164     }
00165     else {
00166         /* This is the main thread.  It runs in the "system"
00167            pthread; no pthread_create is needed.
00168          */
00169 
00170         /* A more elegant solution would be to make a
00171            "fake" stack using the kernel stack origin
00172            and stacksize limit.   This could also allow
00173            the main() stack to have a thread-package size limit,
00174            to catch memory hogs in the main thread. */
00175 
00176         /* The system stack is never virgin */
00177         core->is_virgin = 0;
00178         core->pthread = pthread_self();
00179         core->creator = core->pthread; // main thread
00180     }
00181     return 0;
00182 }
00183 
00184 /* clean up : called on destruction.
00185  * All we do now is join the thread
00186  */
00187 void sthread_core_exit(sthread_core_t* core, bool &joined)
00188 {
00189     void    *join_value=NULL;
00190     if(joined) {
00191         return;
00192     }
00193 
00194     /* must wait for the thread and then harvest its thread */
00195 
00196     if (core->stack_size > 0) {
00197         int res = pthread_join(core->pthread, &join_value);
00198         if(res) {
00199             const char *msg="";
00200             switch(res) {
00201                 case EINVAL:
00202                     msg = "Not a joinable thread: EINVAL";
00203                     break;
00204                 case ESRCH:
00205                     msg = "No such thread: ESRCH";
00206                     break;
00207                 case EDEADLK:
00208                     msg = "Joining with self: EDEADLK";
00209                     break;
00210                 default:
00211                     break;
00212             }
00213             if(res) {
00214                w_ostrstream o;
00215                o << "sthread_core_exit:"
00216                    << " Unexpected result from pthread_join: "
00217                    << msg << " core is : ";
00218 
00219                o << *core << endl;
00220 
00221                W_FATAL_MSG(fcINTERNAL,  << o.c_str() << endl);
00222             }
00223         }
00224         /* And the thread is gone */
00225     }
00226     joined = true;
00227 }
00228 
00229 ostream &operator<<(ostream &o, const sthread_core_t &core)
00230 {
00231     o << "core: ";
00232     if (core.stack_size == 0)
00233         W_FORM(o)("[ system thread %#lx creator %#lx ]", 
00234                 (long) core.pthread, 
00235                 (long) core.creator
00236                 );
00237     else
00238         W_FORM(o)("[ thread %#lx creator %#lx ] size=%d",  
00239             (long) core.pthread, 
00240             (long) core.creator, 
00241             core.stack_size);
00242     if (core.is_virgin)
00243         o << ", virgin-core";
00244     return o;
00245 }

Generated on Thu Dec 9 08:42:27 2010 for Shore Storage Manager by  doxygen 1.4.7