usermode/library/mtm/src/init.c

00001 /*
00002     Copyright (C) 2011 Computer Sciences Department, 
00003     University of Wisconsin -- Madison
00004 
00005     ----------------------------------------------------------------------
00006 
00007     This file is part of Mnemosyne: Lightweight Persistent Memory, 
00008     originally developed at the University of Wisconsin -- Madison.
00009 
00010     Mnemosyne was originally developed primarily by Haris Volos
00011     with contributions from Andres Jaan Tack.
00012 
00013     ----------------------------------------------------------------------
00014 
00015     Mnemosyne is free software; you can redistribute it and/or
00016     modify it under the terms of the GNU General Public License
00017     as published by the Free Software Foundation, version 2
00018     of the License.
00019  
00020     Mnemosyne is distributed in the hope that it will be useful,
00021     but WITHOUT ANY WARRANTY; without even the implied warranty of
00022     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023     GNU General Public License for more details.
00024 
00025     You should have received a copy of the GNU General Public License
00026     along with this program; if not, write to the Free Software
00027     Foundation, Inc., 51 Franklin Street, Fifth Floor, 
00028     Boston, MA  02110-1301, USA.
00029 
00030 ### END HEADER ###
00031 */
00032 
00033 
00034 /*
00035  * Source code is partially derived from TinySTM (license is attached)
00036  *
00037  *
00038  * Author(s):
00039  *   Pascal Felber <pascal.felber@unine.ch>
00040  *
00041  * Copyright (c) 2007-2009.
00042  *
00043  * This program is free software; you can redistribute it and/or
00044  * modify it under the terms of the GNU General Public License
00045  * as published by the Free Software Foundation, version 2
00046  * of the License.
00047  *
00048  * This program is distributed in the hope that it will be useful,
00049  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00050  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00051  * GNU General Public License for more details.
00052  */
00053 
00054 
00055 #include <execinfo.h>
00056 #include <signal.h>
00057 #include <pthread.h>
00058 #include "mtm_i.h"
00059 #include "config.h"
00060 #include "locks.h"
00061 #include "mode/pwb-common/tmlog.h"
00062 #include "sysdeps/x86/target.h"
00063 #include "stats.h"
00064 
00065 static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
00066 volatile uint32_t mtm_initialized = 0;
00067 static int global_num=0;
00068 
00069 m_statsmgr_t *mtm_statsmgr;
00070 
00071 
00072 /*
00073  * Catch signal (to emulate non-faulting load).
00074  */
00075 static 
00076 void 
00077 signal_catcher(int sig)
00078 {
00079         mtm_tx_t *tx = mtm_get_tx();
00080 
00081         /* A fault might only occur upon a load concurrent with a free (read-after-free) */
00082         PRINT_DEBUG("Caught signal: %d\n", sig);
00083 
00084         if (tx == NULL || tx->status == TX_IDLE) {
00085                 /* There is not much we can do: execution will restart at faulty load */
00086                 fprintf(stderr, "Error: invalid memory accessed and no longjmp destination\n");
00087                 exit(1);
00088         }
00089 
00090 #ifdef INTERNAL_STATS
00091         tx->aborts_invalid_memory++;
00092 #endif /* INTERNAL_STATS */
00093         /* Will cause a longjmp */
00094         //FIXME: call restart_transaction
00095         //mtm_rollback(tx);
00096         assert(0);
00097 }
00098 
00099 
00100 
00101 
00102 static inline
00103 void 
00104 init_global()
00105 {
00106 #if CM == CM_PRIORITY
00107         char             *s;
00108 #endif /* CM == CM_PRIORITY */
00109         struct sigaction act;
00110         pcm_storeset_t   *pcm_storeset;
00111 
00112         PRINT_DEBUG("==> mtm_init()\n");
00113         PRINT_DEBUG("\tsizeof(word)=%d\n", (int)sizeof(mtm_word_t));
00114 
00115         COMPILE_TIME_ASSERT(sizeof(mtm_word_t) == sizeof(void *));
00116         COMPILE_TIME_ASSERT(sizeof(mtm_word_t) == sizeof(atomic_t));
00117 
00118         mtm_config_init();
00119 
00120 #ifdef EPOCH_GC
00121         gc_init(mtm_get_clock);
00122 #endif /* EPOCH_GC */
00123 
00124         // Clear the lock bits (and also the write-set bits) for all addresses
00125         // in memory. Because the write-sets are also referenced by this array,
00126         // we must do this even in the case of disabled isolation.
00127         memset((void *)locks, 0, LOCK_ARRAY_SIZE * sizeof(mtm_word_t));
00128 
00129 #if CM == CM_PRIORITY
00130         s = getenv(VR_THRESHOLD);
00131         if (s != NULL) {
00132                 vr_threshold = (int)strtol(s, NULL, 10);
00133         } else {
00134                 vr_threshold = VR_THRESHOLD;
00135         }       
00136         PRINT_DEBUG("\tVR_THRESHOLD=%d\n", vr_threshold);
00137         s = getenv(CM_THRESHOLD);
00138         if (s != NULL) {
00139                 cm_threshold = (int)strtol(s, NULL, 10);
00140         } else {
00141                 cm_threshold = CM_THRESHOLD;
00142         }       
00143         PRINT_DEBUG("\tCM_THRESHOLD=%d\n", cm_threshold);
00144 #endif /* CM == CM_PRIORITY */
00145 
00146         CLOCK = 0;
00147 #ifdef ROLLOVER_CLOCK
00148         if (pthread_mutex_init(&tx_count_mutex, NULL) != 0) {
00149                 fprintf(stderr, "Error creating mutex\n");
00150                 exit(1);
00151         }
00152         if (pthread_cond_init(&tx_reset, NULL) != 0) {
00153                 fprintf(stderr, "Error creating condition variable\n");
00154                 exit(1);
00155         }
00156 
00157         tx_count = 0;
00158         tx_overflow = 0;
00159 #endif /* ROLLOVER_CLOCK */
00160 
00161 #ifndef TLS
00162         if (pthread_key_create(&_mtm_thread_tx, NULL) != 0) {
00163                 fprintf(stderr, "Error creating thread local\n");
00164                 exit(1);
00165         }
00166 #endif /* ! TLS */
00167 
00168         pcm_storeset = pcm_storeset_get ();
00169 
00170         /* Register persistent logical log type with the log manager */
00171         m_logmgr_register_logtype(pcm_storeset, M_TMLOG_LF_TYPE, &M_TMLOG_OPS);
00172         /* Ask log manager to perform recovery on the new log type */
00173         m_logmgr_do_recovery(pcm_storeset);
00174 
00175 #ifdef _M_STATS_BUILD   
00176         /* Create a statistics manager if need to dynamically profile */
00177         if (1) {
00178                 m_statsmgr_create(&mtm_statsmgr, mtm_runtime_settings.stats_file);
00179         }       
00180 #endif  
00181 
00182         /* Catch signals for non-faulting load */
00183         act.sa_handler = signal_catcher;
00184         act.sa_flags = 0;
00185         sigemptyset(&act.sa_mask);
00186         if (sigaction(SIGBUS, &act, NULL) < 0 || sigaction(SIGSEGV, &act, NULL) < 0) {
00187                 perror("sigaction");
00188                 exit(1);
00189         }
00190 }
00191 
00192 
00193 
00194 int 
00195 mtm_init_global(void)
00196 {
00197         if (mtm_initialized) {
00198                 return 0;
00199         }
00200 
00201         pthread_mutex_lock(&global_init_lock);
00202         if (!mtm_initialized) {
00203                 init_global();
00204                 default_dtable_group = &normal_dtable_group;
00205                 mtm_initialized = 1;
00206         }       
00207         pthread_mutex_unlock(&global_init_lock);
00208         return 0;
00209 }
00210 
00211 
00212 void 
00213 fini_global()
00214 {
00215         PRINT_DEBUG("==> mtm_exit()\n");
00216 
00217 #ifndef TLS
00218         pthread_key_delete(_mtm_thread_tx);
00219 #endif /* ! TLS */
00220 #ifdef ROLLOVER_CLOCK
00221         //pthread_cond_destroy(&tx_reset);
00222         pthread_mutex_destroy(&tx_count_mutex);
00223 #endif /* ROLLOVER_CLOCK */
00224 
00225 #ifdef EPOCH_GC
00226         gc_exit();
00227 #endif /* EPOCH_GC */
00228 #ifdef _M_STATS_BUILD   
00229         m_stats_print(mtm_statsmgr);
00230 #endif  
00231 }
00232 
00233 
00234 
00235 void 
00236 mtm_fini_global(void)
00237 {
00238         if (!mtm_initialized) {
00239                 return 0;
00240         }
00241 
00242         pthread_mutex_lock(&global_init_lock);
00243         if (mtm_initialized) {
00244                 fini_global();
00245                 mtm_initialized = 0;
00246         }       
00247         pthread_mutex_unlock(&global_init_lock);
00248         return 0;
00249 }
00250 
00251 
00252 /*
00253  * Called by the CURRENT thread to initialize thread-local STM data.
00254  */
00255 TXTYPE 
00256 mtm_init_thread(void)
00257 {
00258         mtm_tx_t       *tx = mtm_get_tx();
00259         mtm_mode_t     txmode;
00260         pthread_attr_t attr;
00261 
00262 
00263         if (tx) {
00264                 TX_RETURN;
00265         }
00266 
00267         mtm_init_global();
00268 
00269         PRINT_DEBUG("==> mtm_init_thread()\n");
00270 
00271 #ifdef EPOCH_GC
00272         gc_init_thread();
00273 #endif /* EPOCH_GC */
00274 
00275 
00276         /* Allocate descriptor */
00277 #if ALIGNMENT == 1 /* no alignment requirement */
00278         if ((tx = (mtm_tx_t *)malloc(sizeof(mtm_tx_t))) == NULL) {
00279                 perror("malloc");
00280                 exit(1);
00281         }
00282 #else
00283         if (posix_memalign((void **)&tx, ALIGNMENT, sizeof(mtm_tx_t)) != 0) {
00284                 fprintf(stderr, "Error: cannot allocate aligned memory\n");
00285                 exit(1);
00286         }
00287 #endif
00288 
00289         /* Get current thread's PCM emulation bookkeeping structure */
00290         tx->pcm_storeset = pcm_storeset_get();
00291 
00292         /* Set status (no need for CAS or atomic op) */
00293         tx->status = TX_IDLE;
00294 
00295         /* Setup execution mode */
00296 #undef ACTION
00297 #define ACTION(mode) \
00298         mtm_##mode##_create(tx, &(tx->modedata[MTM_MODE_##mode]));
00299         FOREACH_MODE(ACTION)
00300 #undef ACTION  
00301 
00302         txmode = mtm_str2mode(mtm_runtime_settings.force_mode);
00303 
00304         switch (txmode) {
00305                 case MTM_MODE_pwbnl:
00306                         tx->mode = MTM_MODE_pwbnl;
00307                         tx->dtable = default_dtable_group->mtm_pwbnl;
00308                         break;
00309                 case MTM_MODE_pwbetl:
00310                         tx->mode = MTM_MODE_pwbetl;
00311                         tx->dtable = default_dtable_group->mtm_pwbetl;
00312                         break;
00313                 default:
00314                         assert(0); /* unknown transaction mode */
00315         }
00316 
00317 
00318         /* Nesting level */
00319         tx->nesting = 0;
00320 
00322         //memset(tx->data, 0, MAX_SPECIFIC * sizeof(void *));
00323 #ifdef READ_LOCKED_DATA
00324         /* Instance number */
00325         tx->id = 0;
00326 #endif /* READ_LOCKED_DATA */
00327 #ifdef CONFLICT_TRACKING
00328         /* Thread identifier */
00329         tx->thread_id = pthread_self();
00330 #endif /* CONFLICT_TRACKING */
00331 #if CM == CM_DELAY || CM == CM_PRIORITY
00332         /* Contented lock */
00333         tx->c_lock = NULL;
00334 #endif /* CM == CM_DELAY || CM == CM_PRIORITY */
00335 #if CM == CM_BACKOFF
00336         /* Backoff */
00337         tx->backoff = MIN_BACKOFF;
00338         tx->seed = 123456789UL;
00339 #endif /* CM == CM_BACKOFF */
00340 #if CM == CM_PRIORITY
00341         /* Priority */
00342         tx->priority = 0;
00343         tx->visible_reads = 0;
00344 #endif /* CM == CM_PRIORITY */
00345 #if CM == CM_PRIORITY || defined(INTERNAL_STATS)
00346         tx->retries = 0;
00347 #endif /* CM == CM_PRIORITY || defined(INTERNAL_STATS) */
00348 #ifdef INTERNAL_STATS
00349         /* Statistics */
00350         tx->aborts = 0;
00351         tx->aborts_ro = 0;
00352         tx->aborts_locked_read = 0;
00353         tx->aborts_locked_write = 0;
00354         tx->aborts_validate_read = 0;
00355         tx->aborts_validate_write = 0;
00356         tx->aborts_validate_commit = 0;
00357         tx->aborts_invalid_memory = 0;
00358         tx->aborts_reallocate = 0;
00359 # ifdef ROLLOVER_CLOCK
00360         tx->aborts_rollover = 0;
00361 # endif /* ROLLOVER_CLOCK */
00362 # ifdef READ_LOCKED_DATA
00363         tx->locked_reads_ok = 0;
00364         tx->locked_reads_failed = 0;
00365 # endif /* READ_LOCKED_DATA */
00366         tx->max_retries = 0;
00367 #endif /* INTERNAL_STATS */
00368         /* Store as thread-local data */
00369 #ifdef TLS
00370         _mtm_thread_tx = tx;
00371 #else /* ! TLS */
00372         pthread_setspecific(_mtm_thread_tx, tx);
00373 #endif /* ! TLS */
00374 #ifdef ROLLOVER_CLOCK
00375         mtm_rollover_enter(tx);
00376 #endif /* ROLLOVER_CLOCK */
00377 
00378         tx->tmp_jb_ptr = &(tx->tmp_jb);
00379 
00380         tx->stack_base = get_stack_base();
00381         pthread_attr_init(&attr);
00382         pthread_attr_getstacksize(&attr, &tx->stack_size);
00383 
00384         mtm_local_init(tx);
00385 
00386         /* Allocate private write-back table; entries are set to zero by calloc. */
00387         if ((tx->wb_table = (mtm_word_t *)calloc(PRIVATE_LOCK_ARRAY_SIZE, sizeof(mtm_word_t))) == NULL) {
00388                 perror("malloc");
00389                 exit(1);
00390         }       
00391 
00392         mtm_useraction_list_alloc(&tx->commit_action_list);
00393         mtm_useraction_list_alloc(&tx->undo_action_list);
00394 
00395         tx->thread_num = __sync_add_and_fetch (&global_num, 1);
00396 #ifdef _M_STATS_BUILD   
00397         m_stats_threadstat_create(mtm_statsmgr, tx->thread_num, &tx->threadstat);
00398 #endif
00399 
00400         TX_RETURN;
00401 }
00402 
00403 
00404 /*
00405  * Called by the CURRENT thread to cleanup thread-local STM data.
00406  */
00407 void 
00408 mtm_fini_thread(void)
00409 {
00410 #ifdef EPOCH_GC
00411         mtm_word_t t;
00412 #endif /* EPOCH_GC */
00413         mtm_tx_t *tx = mtm_get_tx();
00414 
00415         PRINT_DEBUG("==> mtm_exit_thread(%p)\n", tx);
00416 
00417 #if 0
00418         /* Callbacks */
00419         if (nb_exit_cb != 0) {
00420                 int cb;
00421                 for (cb = 0; cb < nb_exit_cb; cb++) {
00422                         exit_cb[cb].f(TXARGS exit_cb[cb].arg);
00423                 }       
00424         }
00425 #endif  
00426 
00427 #ifdef ROLLOVER_CLOCK
00428         mtm_rollover_exit(tx);
00429 #endif /* ROLLOVER_CLOCK */
00430 
00431         /* Create mode specific descriptors */
00432 #undef ACTION
00433 #define ACTION(mode) \
00434         mtm_##mode##_destroy((mtm_mode_data_t *) tx->modedata[MTM_MODE_##mode]);
00435         FOREACH_MODE(ACTION)
00436 #undef ACTION  
00437 
00438         pcm_storeset_put();
00439 #ifdef EPOCH_GC
00440         t = GET_CLOCK;
00441         gc_free(tx, t);
00442         gc_exit_thread();
00443 #else /* ! EPOCH_GC */
00444         free(tx);
00445 #endif /* ! EPOCH_GC */
00446 }

Generated on Sat Apr 23 11:43:35 2011 for Mnemosyne by  doxygen 1.4.7