Advertisement
Guest User

Untitled

a guest
May 6th, 2012
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.02 KB | None | 0 0
  1. /*
  2.  * Lugh: A utility function library
  3.  * stmtx.c: Software transactional memory
  4.  *
  5.  * Copyright (c) 2012 Patrick McFarland <pmcfarland@adterrasperaspera.com>
  6.  *
  7.  * Permission to use, copy, modify, and/or distribute this software for any
  8.  * purpose with or without fee is hereby granted, provided that the above
  9.  * copyright notice and this permission notice appear in all copies.
  10.  *
  11.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  12.  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  13.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  14.  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
  15.  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  16.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  17.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  18.  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  19.  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  20.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  21.  * POSSIBILITY OF SUCH DAMAGE.
  22.  */
  23.  
  24. #include "lugh.h"
  25.  
  26. typedef struct {
  27.     void *dst;
  28.     void *src;
  29.  
  30.     size_t len;
  31.     size_t size;
  32. } lugh_stmtx_write_data_t;
  33.  
  34. typedef struct {
  35.     lugh_stmtx_write_data_t *data;
  36.    
  37.     unsigned long count;
  38.     unsigned long size;
  39. } lugh_stmtx_write_t;
  40.  
  41. static inline void lugh_stmtx_write_init(lugh_stmtx_write_t *write) {
  42.     write->data = lugh_alloc(sizeof(lugh_stmtx_write_data_t) * 16);
  43.     write->count = 0;
  44.     write->size = 16;
  45. }
  46.  
  47. static inline void lugh_stmtx_write_deinit(lugh_stmtx_write_t *write) {
  48.     for(size_t i = 0; i < write->size; i++)
  49.         if(write->data[i].src != NULL)
  50.             lugh_free(write->data[i].src);
  51.  
  52.     lugh_free(write->data);
  53. }
  54.  
  55. static inline void lugh_stmtx_write_add(lugh_stmtx_write_t *write, void *dst, void *src, size_t len) {
  56.     size_t i;
  57.  
  58.     for(i = 0; i < write->count; i++) {
  59.         if(write->data[i].dst == dst) {
  60.             break;
  61.         }
  62.     }
  63.  
  64.     if(write->data[i].dst != dst)
  65.         write->count++;
  66.  
  67.     if(write->count == write->size) {
  68.         lugh_stmtx_write_data_t *old_write = write->data;
  69.  
  70.         write->size *= 2;
  71.  
  72.         write->data = lugh_alloc(sizeof(lugh_stmtx_write_data_t *) * write->size);
  73.         memcpy(write->data, old_write, sizeof(lugh_stmtx_write_data_t *) * write->size);
  74.  
  75.         lugh_free(old_write);
  76.     }
  77.  
  78.     write->data[write->count].dst = dst;
  79.  
  80.     if(write->data[write->count].size < len) {
  81.         lugh_free(write->data[write->count].src);
  82.         write->data[write->count].src = NULL;
  83.     }
  84.  
  85.     if(write->data[write->count].src == NULL) {
  86.         write->data[write->count].src = lugh_alloc(len);
  87.         write->data[write->count].size = len;
  88.     }
  89.  
  90.     memcpy(write->data[write->count].src, src, len);
  91.  
  92.     write->data[write->count].len = len;
  93. }
  94.  
  95. static inline void lugh_stmtx_write_commit(lugh_stmtx_write_t *write) {
  96.     for(size_t i = 0; i < write->count; i++) {
  97.         memcpy(write->data[i].dst, write->data[i].src, write->data[i].len);
  98.     }
  99. }
  100.  
  101. static inline void lugh_stmtx_write_clear(lugh_stmtx_write_t *write) {
  102.     for(size_t i = 0; i < write->count; i++)
  103.         write->data[i].dst = NULL;
  104.  
  105.     write->count = 0;
  106. }
  107.  
  108. typedef struct {
  109.     uint64_t a;
  110.     uint64_t b;
  111. } lugh_stmtx_filter_t;
  112.  
  113. static inline void lugh_stmtx_filter_init(lugh_stmtx_filter_t *filter) {
  114.     filter->a = 0;
  115.     filter->b = 0;
  116. }
  117.  
  118. static inline void lugh_stmtx_filter_add(lugh_stmtx_filter_t *filter, void *addr) {
  119.     uint64_t h1 = 0x43616B653D4C6965LLU;
  120.     uint64_t h2 = h1;
  121.  
  122.   uint64_t c1 = 0x87c37b91114253d5LLU;
  123.   uint64_t c2 = 0x4cf5ad432745937fLLU;
  124.  
  125.     uint64_t k1 = 0;
  126.  
  127.   k1 = (uint64_t)addr;
  128.   k1 *= c1;
  129.     k1  = ((k1 << 31) | (k1 >> (33)));
  130.     k1 *= c2;
  131.     h1 ^= k1;
  132.  
  133.   h1 ^= 8;
  134.     h2 ^= 8;
  135.  
  136.   h1 += h2;
  137.   h2 += h1;
  138.  
  139.   h1 ^= h1 >> 33;
  140.   h2 ^= h2 >> 33;
  141.   h1 *= 0xff51afd7ed558ccdLLU;
  142.   h2 *= 0xff51afd7ed558ccdLLU;
  143.   h1 ^= h1 >> 33;
  144.   h2 ^= h2 >> 33;
  145.   h1 *= 0xc4ceb9fe1a85ec53LLU;
  146.   h2 *= 0xc4ceb9fe1a85ec53LLU;
  147.   h1 ^= h1 >> 33;
  148.   h2 ^= h2 >> 33;
  149.  
  150.   h1 += h2;
  151.   h2 += h1;
  152.  
  153.     uint64_t b = 1L << (h1 & 0x3f);
  154.  
  155.     if((h1 >> 6) % 2)
  156.         filter->a |= b;
  157.     else
  158.         filter->b |= b;
  159.  
  160.     b = 1L << (h2 & 0x3f);
  161.  
  162.     if((h2 >> 6) % 2)
  163.         filter->a |= b;
  164.     else
  165.         filter->b |= b;
  166. }
  167.  
  168. static inline bool lugh_stmtx_filter_intersect(lugh_stmtx_filter_t *filter1, lugh_stmtx_filter_t *filter2) {
  169.     return (filter1->a & filter2->a) || (filter1->b & filter2->b);
  170. }
  171.  
  172. typedef unsigned int lugh_stmtx_ts_t;
  173.  
  174. typedef enum {
  175.     LUGH_STMTX_COMMIT_ACTIVE,
  176.     LUGH_STMTX_COMMIT_COMPLETE
  177. } lugh_stmtx_commit_state_t;
  178.  
  179. typedef struct {
  180.     lugh_stmtx_ts_t start;
  181.     lugh_stmtx_commit_state_t state;
  182.   lugh_stmtx_filter_t filter;
  183.     lugh_stmtx_access_t access;
  184. } lugh_stmtx_commit_t;
  185.  
  186. #define COMMITS 8
  187.  
  188. lugh_stmtx_commit_t ring[COMMITS];
  189. lugh_atomic(lugh_stmtx_ts_t) ring_index;
  190. lugh_atomic(lugh_stmtx_ts_t) prefix_index;
  191.  
  192. struct _lugh_stmtx {
  193.     lugh_stmtx_ts_t start;
  194.     lugh_stmtx_write_t write;
  195.     lugh_stmtx_filter_t filter;
  196.     lugh_stmtx_access_t access;
  197. };
  198.  
  199. void lugh_stmtx_bootstrap(void) {
  200.     ring_index = 0;
  201.     prefix_index = 0;
  202.    
  203.     for(int i = 0; i < COMMITS; i++) {
  204.         ring[i].start = 0;
  205.         ring[i].state = LUGH_STMTX_COMMIT_COMPLETE;
  206.         lugh_stmtx_filter_init(&ring[i].filter);
  207.         ring[i].access = LUGH_STMTX_ACCESS_RW;
  208.     }
  209. }
  210.  
  211. int lugh_stmtx_init(lugh_stmtx_t* tx) {
  212.     return_val_if_fail(tx != NULL, -1);
  213.  
  214.     tx->start = 0;
  215.     lugh_stmtx_write_init(&tx->write);
  216.     lugh_stmtx_filter_init(&tx->filter);
  217.     tx->access = LUGH_STMTX_ACCESS_RW;
  218.  
  219.     return 0;
  220. }
  221.  
  222. lugh_stmtx_t *lugh_stmtx_create(void) {
  223.     lugh_stmtx_t *tx = lugh_alloc(sizeof(lugh_stmtx_t));
  224.  
  225.     if(lugh_stmtx_init(tx) == 0) {
  226.         return tx;
  227.     } else {
  228.         lugh_free(tx);
  229.         return NULL;
  230.     }
  231. }
  232.  
  233. void lugh_stmtx_deinit(lugh_stmtx_t *tx) {
  234.     return_if_fail(tx != NULL);
  235.  
  236.     lugh_stmtx_write_deinit(&tx->write);
  237. }
  238.  
  239. void lugh_stmtx_destroy(lugh_stmtx_t *tx) {
  240.     return_if_fail(tx != NULL);
  241.  
  242.     lugh_stmtx_deinit(tx);
  243.  
  244.     lugh_free(tx);
  245. }
  246.  
  247. int lugh_stmtx_begin(lugh_stmtx_t *tx, lugh_stmtx_access_t access) {
  248.     return_val_if_fail(tx != NULL, -1);
  249.    
  250.     tx->start = lugh_atomic_load_uint(&prefix_index);
  251.  
  252.     while(ring[(tx->start + 1) % COMMITS].state == LUGH_STMTX_COMMIT_COMPLETE &&
  253.               ring[(tx->start + 1) % COMMITS].start > tx->start) {
  254.         tx->start++;
  255.     }
  256.  
  257.     tx->access = access;
  258.  
  259.     return 0;
  260. }
  261.  
  262. void lugh_stmtx_abort(lugh_stmtx_t *tx) {
  263.     return_if_fail(tx != NULL);
  264.  
  265.     lugh_stmtx_write_clear(&tx->write);
  266.     lugh_stmtx_filter_init(&tx->filter);
  267. }
  268.  
  269. lugh_stmtx_state_t lugh_stmtx_check(lugh_stmtx_t *tx) {
  270.     return_val_if_fail(tx != NULL, LUGH_STMTX_STATE_ERROR);
  271.  
  272.     if(ring_index == tx->start)
  273.         return LUGH_STMTX_STATE_VIABLE;
  274.  
  275.     lugh_stmtx_ts_t suffix_end = ring_index;
  276.  
  277.     while(ring[suffix_end % COMMITS].start < suffix_end);
  278.  
  279.     for(lugh_stmtx_ts_t i = ring_index; i >= tx->start + 1; i--) {
  280.         if(!(tx->access == LUGH_STMTX_ACCESS_RO && ring[i % COMMITS].access == LUGH_STMTX_ACCESS_RO) &&
  281.                 lugh_stmtx_filter_intersect(&tx->filter, &ring[i % COMMITS].filter)) {
  282.             lugh_stmtx_abort(tx);
  283.             return LUGH_STMTX_STATE_ABORTED;
  284.         }
  285.  
  286.         if(ring[i % COMMITS].state == LUGH_STMTX_COMMIT_ACTIVE)
  287.             suffix_end = i - 1;
  288.     }
  289.                
  290.     tx->start = suffix_end;
  291.  
  292.     return LUGH_STMTX_STATE_VIABLE;
  293. }
  294.  
  295. lugh_stmtx_state_t lugh_stmtx_write(lugh_stmtx_t *tx, void *dst, void *src, size_t size) {
  296.     return_val_if_fail(tx != NULL, LUGH_STMTX_STATE_ERROR);
  297.    
  298.     lugh_stmtx_filter_add(&tx->filter, dst);
  299.  
  300.     lugh_stmtx_write_add(&tx->write, dst, src, size);
  301.  
  302.     return LUGH_STMTX_STATE_VIABLE;
  303. }
  304.  
  305. lugh_stmtx_state_t lugh_stmtx_read(lugh_stmtx_t *tx, void *dst, void *src, size_t size) {
  306.     return_val_if_fail(tx != NULL, LUGH_STMTX_STATE_ERROR);
  307.  
  308.     if(lugh_stmtx_check(tx) == LUGH_STMTX_STATE_ABORTED)
  309.         return LUGH_STMTX_STATE_ABORTED;
  310.  
  311.     lugh_stmtx_filter_add(&tx->filter, src);
  312.  
  313.     return LUGH_STMTX_STATE_VIABLE;
  314. }
  315.  
  316. lugh_stmtx_state_t lugh_stmtx_commit(lugh_stmtx_t *tx) {
  317.     return_val_if_fail(tx != NULL, LUGH_STMTX_STATE_ERROR);
  318.  
  319.     if(tx->write.count == 0) {
  320.  
  321.         return LUGH_STMTX_STATE_COMMITTED;
  322.     }
  323.  
  324.     lugh_stmtx_ts_t commit_time = ring_index;
  325.  
  326.     do {
  327.         if(lugh_stmtx_check(tx) == LUGH_STMTX_STATE_ABORTED)
  328.             return LUGH_STMTX_STATE_ABORTED;
  329.     }   while(lugh_atomic_compare_exchange_uint(&ring_index, commit_time, commit_time + 1) != commit_time);
  330.  
  331.     commit_time++;
  332.  
  333.     lugh_stmtx_ts_t index_time = commit_time % COMMITS;
  334.  
  335.     ring[index_time].state = LUGH_STMTX_COMMIT_ACTIVE;
  336.     ring[index_time].start = commit_time;
  337.    
  338.     lugh_atomic_synchronize();
  339.  
  340.     for(lugh_stmtx_ts_t i = commit_time; i > tx->start; i--) {
  341.         if(!(tx->access == LUGH_STMTX_ACCESS_RO && ring[i % COMMITS].access == LUGH_STMTX_ACCESS_RO) &&
  342.                 lugh_stmtx_filter_intersect(&tx->filter, &ring[i % COMMITS].filter))
  343.             while(ring[i % COMMITS].state == LUGH_STMTX_COMMIT_ACTIVE);
  344.     }
  345.  
  346.     lugh_stmtx_write_commit(&tx->write);
  347.  
  348.     ring[index_time].filter.a = 0;
  349.     ring[index_time].filter.b = 0;
  350.     ring[index_time].state = LUGH_STMTX_COMMIT_COMPLETE;
  351.  
  352.     if(prefix_index < tx->start)
  353.         prefix_index = tx->start;
  354.  
  355.     lugh_atomic_synchronize();
  356.    
  357.     lugh_stmtx_write_clear(&tx->write);
  358.     lugh_stmtx_filter_init(&tx->filter);
  359.  
  360.     return LUGH_STMTX_STATE_COMMITTED;
  361. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement