usermode/library/mtm/src/mtm_i.h

Go to the documentation of this file.
00001 
00008 /*
00009  * Source code is partially derived from TinySTM (license is attached)
00010  *
00011  * Author(s):
00012  *   Pascal Felber <pascal.felber@unine.ch>
00013  *
00014  * Copyright (c) 2007-2009.
00015  *
00016  * This program is free software; you can redistribute it and/or
00017  * modify it under the terms of the GNU General Public License
00018  * as published by the Free Software Foundation, version 2
00019  * of the License.
00020  *
00021  * This program is distributed in the hope that it will be useful,
00022  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00023  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024  * GNU General Public License for more details.
00025  */
00026 
00027 #ifndef _MTM_I_H_819AKI 
00028 #define _MTM_I_H_819AKI 
00029 
00030 #include <stddef.h>
00031 #include <stdbool.h>
00032 #include <stdint.h>
00033 
00034 #define ITM_NORETURN    __attribute__((noreturn))
00035 
00036 #include <xmmintrin.h>
00037 
00038 typedef uint8_t              _ITM_TYPE_U1;
00039 typedef uint16_t             _ITM_TYPE_U2;
00040 typedef uint32_t             _ITM_TYPE_U4;
00041 typedef uint64_t             _ITM_TYPE_U8;
00042 typedef float                _ITM_TYPE_F;
00043 typedef double               _ITM_TYPE_D;
00044 typedef long double          _ITM_TYPE_E;
00045 typedef __m64                _ITM_TYPE_M64;
00046 typedef __m128               _ITM_TYPE_M128;
00047 typedef float _Complex       _ITM_TYPE_CF;
00048 typedef double _Complex      _ITM_TYPE_CD;
00049 typedef long double _Complex _ITM_TYPE_CE;
00050 
00051 typedef struct mtm_tx_s mtm_tx_t;
00052 typedef mtm_tx_t _ITM_transaction;
00053 
00054 #include "itm.h"
00055 
00056 # ifndef __cplusplus
00057 #  define FOR_ALL_TYPES(ACTION,name)    \
00058 ACTION (name,uint8_t,U1)                \
00059 ACTION (name,uint16_t,U2)               \
00060 ACTION (name,uint32_t,U4)               \
00061 ACTION (name,uint64_t,U8)               \
00062 ACTION (name,float,F)                   \
00063 ACTION (name,double,D)                  \
00064 ACTION (name,long double,E)             \
00065 ACTION (name,__m64,M64)                 \
00066 ACTION (name,__m128,M128)               \
00067 ACTION (name,float _Complex,CF)         \
00068 ACTION (name,double _Complex,CD)        \
00069 ACTION (name,long double _Complex,CE)
00070 # else
00071 #  define FOR_ALL_TYPES(ACTION,name)    \
00072 ACTION (name,uint8_t,U1)                \
00073 ACTION (name,uint16_t,U2)               \
00074 ACTION (name,uint32_t,U4)               \
00075 ACTION (name,uint64_t,U8)               \
00076 ACTION (name,float,F)                   \
00077 ACTION (name,double,D)                  \
00078 ACTION (name,long double,E)             \
00079 ACTION (name,__m64,M64)                 \
00080 ACTION (name,__m128,M128)
00081 # endif
00082 
00083 #include <result.h>
00084 
00085 
00086 /* Persistent log type */
00087 #define TMLOG_TYPE_BASE    0
00088 #define TMLOG_TYPE_TORNBIT 1
00089 
00090 #if TMLOG_TYPE == TMLOG_TYPE_BASE
00091 # define M_TMLOG_WRITE          m_tmlog_base_write
00092 # define M_TMLOG_TRUNCATE_SYNC  m_tmlog_base_truncate_sync
00093 # define M_TMLOG_BEGIN          m_tmlog_base_begin
00094 # define M_TMLOG_COMMIT         m_tmlog_base_commit
00095 # define M_TMLOG_ABORT          m_tmlog_base_abort
00096 # define M_TMLOG_T              m_tmlog_base_t
00097 # define M_TMLOG_LF_TYPE        LF_TYPE_TM_BASE
00098 # define M_TMLOG_OPS            tmlog_base_ops
00099 #elif TMLOG_TYPE == TMLOG_TYPE_TORNBIT
00100 # define M_TMLOG_WRITE          m_tmlog_tornbit_write
00101 # define M_TMLOG_TRUNCATE_SYNC  m_tmlog_tornbit_truncate_sync
00102 # define M_TMLOG_BEGIN          m_tmlog_tornbit_begin
00103 # define M_TMLOG_COMMIT         m_tmlog_tornbit_commit
00104 # define M_TMLOG_ABORT          m_tmlog_tornbit_abort
00105 # define M_TMLOG_T              m_tmlog_tornbit_t
00106 # define M_TMLOG_LF_TYPE        LF_TYPE_TM_TORNBIT
00107 # define M_TMLOG_OPS            tmlog_tornbit_ops
00108 #else
00109 # error "Unknown persistent log type."
00110 #endif
00111 
00112 /*
00113  * The library does not require to pass the current transaction as a
00114  * parameter to the functions (the current transaction is stored in a
00115  * thread-local variable).  One can, however, compile the library with
00116  * explicit transaction parameters.  This is useful, for instance, for
00117  * performance on architectures that do not support TLS or for easier
00118  * compiler integration.
00119  */
00120 #define EXPLICIT_TX_PARAMETER
00121 
00122 # ifdef EXPLICIT_TX_PARAMETER
00123 #  define TXTYPE                        mtm_tx_t *
00124 #  define TXPARAM                       mtm_tx_t *tx
00125 #  define TXPARAMS                      mtm_tx_t *tx,
00126 #  define TXARG                         (mtm_tx_t *)tx
00127 #  define TXARGS                        (mtm_tx_t *)tx,
00128 struct mtm_tx *mtm_current_tx();
00129 # else /* ! EXPLICIT_TX_PARAMETER */
00130 #  define TXTYPE                        void
00131 #  define TXPARAM                       /* Nothing */
00132 #  define TXPARAMS                      /* Nothing */
00133 #  define TXARG                         /* Nothing */
00134 #  define TXARGS                        /* Nothing */
00135 #endif /* ! EXPLICIT_TX_PARAMETER */
00136 
00137 #ifdef EXPLICIT_TX_PARAMETER
00138 # define TX_RETURN                      return tx
00139 # define TX_GET                         /* Nothing */
00140 #else /* ! EXPLICIT_TX_PARAMETER */
00141 # define TX_RETURN                      return
00142 # define TX_GET                         mtm_tx_t *tx = mtm_get_tx()
00143 #endif /* ! EXPLICIT_TX_PARAMETER */
00144 
00145 #define WRITE_BACK_ETL                  0
00146 #define WRITE_THROUGH                   1
00147 
00148 #define CM_SUICIDE                      0
00149 #define CM_DELAY                        1
00150 #define CM_BACKOFF                      2
00151 #define CM_PRIORITY                     3
00152 
00153 #include <assert.h>
00154 #include <stdio.h>
00155 #include <stdlib.h>
00156 #include <string.h>
00157 //#include <unwind.h>
00158 #include <pthread.h>
00159 
00160 #include <atomic.h>
00161 
00162 #include <pcm.h>
00163 
00164 #include "mode/dtable.h"
00165 
00166 #if defined(CONFLICT_TRACKING) && ! defined(EPOCH_GC)
00167 # error "CONFLICT_TRACKING requires EPOCH_GC"
00168 #endif /* defined(CONFLICT_TRACKING) && ! defined(EPOCH_GC) */
00169 
00170 #if defined(READ_LOCKED_DATA) && ! defined(EPOCH_GC)
00171 # error "READ_LOCKED_DATA requires EPOCH_GC"
00172 #endif /* defined(READ_LOCKED_DATA) && ! defined(EPOCH_GC) */
00173 
00174 #define TLS
00175 
00176 # define MTM_DEBUG_PRINT(...)
00177 //# define MTM_DEBUG_PRINT(...)               printf(__VA_ARGS__); fflush(NULL)
00178 
00179 #ifdef DEBUG
00180 /* Note: stdio is thread-safe */
00181 # define IO_FLUSH                       fflush(NULL)
00182 # define PRINT_DEBUG(...)               printf(__VA_ARGS__); fflush(NULL)
00183 #else /* ! DEBUG */
00184 # define IO_FLUSH
00185 # define PRINT_DEBUG(...)
00186 #endif /* ! DEBUG */
00187 
00188 #ifdef DEBUG2
00189 # define PRINT_DEBUG2(...)              PRINT_DEBUG(__VA_ARGS__)
00190 #else /* ! DEBUG2 */
00191 # define PRINT_DEBUG2(...)
00192 #endif /* ! DEBUG2 */
00193 
00194 #ifndef LOCK_SHIFT_EXTRA
00195 # define LOCK_SHIFT_EXTRA               2                   /* 2 extra shift */
00196 #endif /* LOCK_SHIFT_EXTRA */
00197 
00198 #if CM == CM_PRIORITY
00199 # define VR_THRESHOLD                   "VR_THRESHOLD"
00200 # define CM_THRESHOLD                   "CM_THRESHOLD"
00201 #endif
00202 
00203 extern int vr_threshold;
00204 extern int cm_threshold;
00205 
00206 
00207 
00208 #define STR2(str1, str2)                str1##str2
00209 #define XSTR(s)                         STR(s)
00210 #define STR(s)                          #s
00211 
00212 #define COMPILE_TIME_ASSERT(pred)       switch (0) { case 0: case pred: ; }
00213 
00214 #define UNUSED          __attribute__((unused))
00215 
00216 #ifdef HAVE_ATTRIBUTE_VISIBILITY
00217 # pragma GCC visibility push(hidden)
00218 #endif
00219 
00220 #include "mode/mode.h"
00221 #include "sysdeps/x86/target.h"
00222 #include "rwlock.h"
00223 #include "useraction.h"
00224 #include "locks.h"
00225 #include "local.h"
00226 #include "stats.h"
00227 
00232 typedef uintptr_t mtm_word_t;
00233 
00234 enum {                                  /* Transaction status */
00235   TX_IDLE = 0,
00236   TX_ACTIVE = 1,
00237   TX_COMMITTED = 2,
00238   TX_ABORTED = 3,
00239   TX_IRREVOCABLE = 4,
00240   TX_SERIAL = 8,
00241 };
00242 
00243 
00244 /* 
00245  * These values are given to mtm_restart_transaction and indicate the
00246  * reason for the restart.  The reason is used to decide what STM 
00247  * implementation should be used during the next iteration.  
00248  */
00249 typedef enum mtm_restart_reason
00250 {
00251         RESTART_REALLOCATE,
00252         RESTART_LOCKED_READ,
00253         RESTART_LOCKED_WRITE,
00254         RESTART_VALIDATE_READ,
00255         RESTART_VALIDATE_WRITE,
00256         RESTART_VALIDATE_COMMIT,
00257         RESTART_NOT_READONLY,
00258         RESTART_USER_RETRY,
00259         NUM_RESTARTS
00260 } mtm_restart_reason;
00261 
00262 
00263 /* This type is private to local.c.  */
00264 struct mtm_local_undo;
00265 
00266 /* Transaction descriptor */
00267 struct mtm_tx_s {
00268         uintptr_t              dummy1;           /* ICC expects to find the dtable pointer at offset 2*WORD_SIZE. */
00269         uintptr_t              dummy2;
00270         mtm_dtable_t           *dtable;          /* The dispatch table for the active transaction mode. */
00271 
00272         mtm_jmpbuf_t           *tmp_jb_ptr;      /* Pointer to the temporary register checkpoint. This simplifies the assembly checkpoint code. */
00273         mtm_jmpbuf_t           tmp_jb;           /* Temporary register checkpoint; this is where the assebly register checkpoint code will save the registers.  */
00274         mtm_jmpbuf_t           jb;               /* Register checkpoint of this transaction. Keeping this separate from tmp_jb allows a nested transaction to transparently execute the assembly checkpoint code without destroying the active register checkpoint.  */
00275 
00276         mtm_mode_data_t        *modedata[MTM_NUM_MODES];
00277         mtm_mode_t             mode;
00278         mtm_word_t             status;           /* Transaction status (not read by other threads). */
00279 
00280         uint32_t               prop;             /* The _ITM_codeProperties of this transaction as given by the compiler.  */
00281         int                    nesting;          /* Nesting level. */
00282         int                    can_extend;       /* Can this transaction be extended? */
00283         _ITM_transactionId     id;               /* Instance number of the transaction */
00284         int                    thread_num;
00285 #ifdef CONFLICT_TRACKING
00286         pthread_t              thread_id;        /* Thread identifier (immutable) */
00287 #endif /* CONFLICT_TRACKING */
00288 #if CM == CM_DELAY || CM == CM_PRIORITY
00289         volatile mtm_word_t    *c_lock;          /* Pointer to contented lock (cause of abort). */
00290 #endif /* CM == CM_DELAY || CM == CM_PRIORITY */
00291 #if CM == CM_BACKOFF
00292         unsigned long          backoff;          /* Maximum backoff duration. */
00293         unsigned long          seed;             /* RNG seed. */
00294 #endif /* CM == CM_BACKOFF */
00295 #if CM == CM_PRIORITY
00296         int                    priority;         /* Transaction priority */
00297         int                    visible_reads;    /* Should we use visible reads? */
00298 #endif /* CM == CM_PRIORITY */
00299         unsigned long          retries;          /* Number of consecutive aborts (retries) */
00300 
00301         uintptr_t              stack_base;       /* Stack base address */
00302         uintptr_t              stack_size;       /* Stack size */
00303         mtm_local_undo_t       local_undo;       /* Data used by local.c for the local memory undo log.  */
00304         mtm_word_t             *wb_table;        /* Private write-back table for use when isolation is off. */
00305         pcm_storeset_t         *pcm_storeset;    /* PCM emulation bookkeeping structure */
00306         m_stats_threadstat_t   *threadstat;      /* Thread statistics */
00307         m_stats_statset_t      *statset;         /* Per transaction instance statistics */
00308         mtm_user_action_list_t *commit_action_list;
00309         mtm_user_action_list_t *undo_action_list;
00310 };
00311 
00312 
00313 /*
00314  * Transaction nesting is supported in a minimalist way (flat nesting):
00315  * - When a transaction is started in the context of another
00316  *   transaction, we simply increment a nesting counter but do not
00317  *   actually start a new transaction.
00318  * - The environment to be used for setjmp/longjmp is only returned when
00319  *   no transaction is active so that it is not overwritten by nested
00320  *   transactions. This allows for composability as the caller does not
00321  *   need to know whether it executes inside another transaction.
00322  * - The commit of a nested transaction simply decrements the nesting
00323  *   counter. Only the commit of the top-level transaction will actually
00324  *   carry through updates to shared memory.
00325  * - An abort of a nested transaction will rollback the top-level
00326  *   transaction and reset the nesting counter. The call to longjmp will
00327  *   restart execution before the top-level transaction.
00328  * Using nested transactions without setjmp/longjmp is not recommended
00329  * as one would need to explicitly jump back outside of the top-level
00330  * transaction upon abort of a nested transaction. This breaks
00331  * composability.
00332  */
00333 
00334 /*
00335  * Reading from the previous version of locked addresses is implemented
00336  * by peeking into the write set of the transaction that owns the
00337  * lock. Each transaction has a unique identifier, updated even upon
00338  * retry. A special "commit" bit of this identifier is set upon commit,
00339  * right before writing the values from the redo log to shared memory. A
00340  * transaction can read a locked address if the identifier of the owner
00341  * does not change between before and after reading the value and
00342  * version, and it does not have the commit bit set.
00343  */
00344 
00372 extern volatile mtm_word_t locks[];
00373 
00374 #ifdef CLOCK_IN_CACHE_LINE
00375 extern volatile mtm_word_t gclock[];
00376 # define CLOCK                          (gclock[512 / sizeof(mtm_word_t)])
00377 #else /* ! CLOCK_IN_CACHE_LINE */
00378 extern volatile mtm_word_t gclock;
00379 # define CLOCK                          (gclock)
00380 #endif /* ! CLOCK_IN_CACHE_LINE */
00381 
00382 #ifdef _M_STATS_BUILD   
00383 extern m_statsmgr_t *mtm_statsmgr;
00384 #endif
00385 
00386 /* 
00387  * The lock that provides access to serial mode.  Non-serialized transactions
00388  * acquire read locks; the serialized transaction aquires a write lock.
00389  */
00390 extern mtm_rwlock_t mtm_serial_lock;
00391 
00392 extern uint32_t mtm_begin_transaction(uint32_t, const mtm_jmpbuf_t *);
00393 extern uint32_t mtm_longjmp (const mtm_jmpbuf_t *, uint32_t)
00394         ITM_NORETURN;
00395 
00396 extern void mtm_commit_local (TXPARAM);
00397 extern void mtm_rollback_local (TXPARAM);
00398 extern void mtm_LB (mtm_tx_t *tx, const void *, size_t) _ITM_CALL_CONVENTION;
00399 
00400 extern void mtm_serialmode (bool, bool);
00401 extern void mtm_restart_transaction (mtm_restart_reason) ITM_NORETURN;
00402 
00403 extern void mtm_alloc_record_allocation (void *, size_t, void (*)(void *));
00404 extern void mtm_alloc_forget_allocation (void *, void (*)(void *));
00405 extern size_t mtm_alloc_get_allocation_size (void *);
00406 extern void mtm_alloc_commit_allocations (bool);
00407 
00408 extern void mtm_revert_cpp_exceptions (void);
00409 
00410 //extern mtm_cacheline_page *mtm_page_alloc (void);
00411 //extern void mtm_page_release (mtm_cacheline_page *, mtm_cacheline_page *);
00412 
00413 //extern mtm_cacheline *mtm_null_read_lock (mtm_tx_t *td, uintptr_t);
00414 //extern mtm_cacheline_mask_pair mtm_null_write_lock (mtm_tx_t *td, uintptr_t);
00415 extern void *mtm_null_read_lock (mtm_tx_t *td, uintptr_t);
00416 extern void *mtm_null_write_lock (mtm_tx_t *td, uintptr_t);
00417 
00418 
00419 /* ################################################################### *
00420  * CLOCK
00421  * ################################################################### */
00422 
00423 #define GET_CLOCK                       (ATOMIC_LOAD_ACQ(&CLOCK))
00424 #define FETCH_INC_CLOCK                 (ATOMIC_FETCH_INC_FULL(&CLOCK))
00425 
00426 
00427 /* ################################################################### *
00428  * STATIC
00429  * ################################################################### */
00430 
00431 /* Don't access this variable directly; use the functions below.  */
00432 #ifdef TLS
00433 extern __thread mtm_tx_t *_mtm_thread_tx;
00434 #else /* !TLS */
00435 extern pthread_key_t _mtm_thread_tx;
00436 #endif /* !TLS */
00437 
00438 /*
00439  * Returns the transaction descriptor for the CURRENT thread.
00440  */
00441 static inline mtm_tx_t *mtm_get_tx()
00442 {
00443 #ifdef TLS
00444   return _mtm_thread_tx;
00445 #else /* ! TLS */
00446   return (mtm_tx_t *)pthread_getspecific(_mtm_thread_tx);
00447 #endif /* ! TLS */
00448 }
00449 
00450 #ifdef LOCK_IDX_SWAP
00451 /*
00452  * Compute index in lock table (swap bytes to avoid consecutive addresses to have neighboring locks).
00453  */
00454 static inline unsigned int lock_idx_swap(unsigned int idx) {
00455   return (idx & ~(unsigned int)0xFFFF) | ((idx & 0x00FF) << 8) | ((idx & 0xFF00) >> 8);
00456 }
00457 #endif /* LOCK_IDX_SWAP */
00458 
00459 #ifdef ROLLOVER_CLOCK
00460 /*
00461  * We use a simple approach for clock roll-over:
00462  * - We maintain the count of (active) transactions using a counter
00463  *   protected by a mutex. This approach is not very efficient but the
00464  *   cost is quickly amortized because we only modify the counter when
00465  *   creating and deleting a transaction descriptor, which typically
00466  *   happens much less often than starting and committing a transaction.
00467  * - We detect overflows when reading the clock or when incrementing it.
00468  *   Upon overflow, we wait until all threads have blocked on a barrier.
00469  * - Threads can block on the barrier upon overflow when they (1) start
00470  *   a transaction, or (2) delete a transaction. This means that threads
00471  *   must ensure that they properly delete their transaction descriptor
00472  *   before performing any blocking operation outside of a transaction
00473  *   in order to guarantee liveness (our model prohibits blocking
00474  *   inside a transaction).
00475  */
00476 
00477 pthread_mutex_t tx_count_mutex;
00478 pthread_cond_t tx_reset;
00479 int tx_count;
00480 int tx_overflow;
00481 
00482 /*
00483  * Enter new transactional thread.
00484  */
00485 static inline void mtm_rollover_enter(mtm_tx_t *tx)
00486 {
00487   PRINT_DEBUG("==> mtm_rollover_enter(%p)\n", tx);
00488 
00489   pthread_mutex_lock(&tx_count_mutex);
00490   while (tx_overflow != 0)
00491     pthread_cond_wait(&tx_reset, &tx_count_mutex);
00492   /* One more (active) transaction */
00493   tx_count++;
00494   pthread_mutex_unlock(&tx_count_mutex);
00495 }
00496 
00497 /*
00498  * Exit transactional thread.
00499  */
00500 static inline void mtm_rollover_exit(mtm_tx_t *tx)
00501 {
00502   PRINT_DEBUG("==> mtm_rollover_exit(%p[%lu-%lu])\n", tx, (unsigned long)tx->start, (unsigned long)tx->end);
00503 
00504   pthread_mutex_lock(&tx_count_mutex);
00505   /* One less (active) transaction */
00506   tx_count--;
00507   assert(tx_count >= 0);
00508   /* Are all transactions stopped? */
00509   if (tx_overflow != 0 && tx_count == 0) {
00510     /* Yes: reset clock */
00511     memset((void *)locks, 0, LOCK_ARRAY_SIZE * sizeof(mtm_word_t));
00512     CLOCK = 0;
00513     tx_overflow = 0;
00514 # ifdef EPOCH_GC
00515     /* Reset GC */
00516     gc_reset();
00517 # endif /* EPOCH_GC */
00518     /* Wake up all thread */
00519     pthread_cond_broadcast(&tx_reset);
00520   }
00521   pthread_mutex_unlock(&tx_count_mutex);
00522 }
00523 
00532 static inline void mtm_overflow(mtm_tx_t *tx)
00533 {
00534   PRINT_DEBUG("==> mtm_overflow(%p[%lu-%lu])\n", tx, (unsigned long)tx->start, (unsigned long)tx->end);
00535 
00536   pthread_mutex_lock(&tx_count_mutex);
00537   /* Set overflow flag (might already be set) */
00538   tx_overflow = 1;
00539   /* One less (active) transaction */
00540   tx_count--;
00541   assert(tx_count >= 0);
00542   /* Are all transactions stopped? */
00543   if (tx_count == 0) {
00544     /* Yes: reset clock */
00545     memset((void *)locks, 0, LOCK_ARRAY_SIZE * sizeof(mtm_word_t));
00546     CLOCK = 0;
00547     tx_overflow = 0;
00548 # ifdef EPOCH_GC
00549     /* Reset GC */
00550     gc_reset();
00551 # endif /* EPOCH_GC */
00552     /* Wake up all thread */
00553     pthread_cond_broadcast(&tx_reset);
00554   } else {
00555     /* No: wait for other transactions to stop */
00556     pthread_cond_wait(&tx_reset, &tx_count_mutex);
00557   }
00558   /* One more (active) transaction */
00559   tx_count++;
00560   pthread_mutex_unlock(&tx_count_mutex);
00561 }
00562 #endif /* ROLLOVER_CLOCK */
00563 
00564 /*
00565  * Get curent value of global clock.
00566  */
00567 static inline mtm_word_t mtm_get_clock()
00568 {
00569   return GET_CLOCK;
00570 }
00571 
00572 #ifdef HAVE_ATTRIBUTE_VISIBILITY
00573 # pragma GCC visibility pop
00574 #endif
00575 
00576 #endif /* _MTM_I_H_819AKI */

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