Mercurial > repos > rhope
view runtime/transaction.c @ 189:d0e3a13c1bd9 default tip
Remove old calculator example
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 07 Oct 2011 00:24:04 -0700 |
parents | ba35ab624ec2 |
children |
line wrap: on
line source
#include "transaction.h" #include <stdarg.h> #include <string.h> #ifdef USE_GC #include <gc/gc.h> #else #include <stdlib.h> #endif rh_mutex(trans_lock) trans_cell * find_obj_cell(transaction * trans, mutable_object * to_find) { int32_t idx; while(trans) { for (idx = 0; idx < trans->num_cells; ++idx) if (trans->cells[idx].obj = to_find) return &(trans->cells[idx]); trans = trans->chain; } return NULL; } #ifdef RAW_FUNC transaction * cur_transaction; void real_begin_transaction(int numobjs,...) #else void begin_transaction(context * ct, int numobjs,...) #endif { mutable_object *obj; transaction *parent; va_list args; int32_t idx,got_global_lock=0; parent = cur_transaction ? cur_transaction : NULL; #ifdef USE_GC cur_transaction = GC_malloc(sizeof(transaction)+((numobjs-1)*sizeof(trans_cell))); #else cur_transaction = malloc(sizeof(transaction)+((numobjs-1)*sizeof(trans_cell))); #endif cur_transaction->parent = parent; cur_transaction->chain = NULL; rh_mutex_init(ct->lock); cur_transaction->num_cells = numobjs; va_start(args, numobjs); if (parent) { rh_lock(parent->lock); for (idx = 0; idx < numobjs; ++idx) { obj = va_arg(args, mutable_object *); cur_transaction->cells[idx].obj = obj; cur_transaction->cells[idx].parent = find_obj_cell(parent, obj); if (cur_transaction->cells[idx].parent) { cur_transaction->cells[idx].local_data = cur_transaction->cells[idx].parent->local_data; cur_transaction->cells[idx].orig_version = cur_transaction->cells[idx].parent->local_version; } else { if (!got_global_lock) { rh_lock(trans_lock); got_global_lock = 1; } cur_transaction->cells[idx].local_data = obj->data; cur_transaction->cells[idx].orig_version = obj->version; } cur_transaction->cells[idx].local_version = 0; } if (got_global_lock) { rh_unlock(trans_lock); } rh_unlock(parent->lock); } else { rh_lock(trans_lock); for (idx = 0; idx < numobjs; ++idx) { obj = va_arg(args, mutable_object *); cur_transaction->cells[idx].obj = obj; cur_transaction->cells[idx].parent = NULL; cur_transaction->cells[idx].local_data = add_ref(obj->data); cur_transaction->cells[idx].orig_version = obj->version; cur_transaction->cells[idx].local_version = 0; } rh_unlock(trans_lock); } } #ifdef USE_GC #define free_trans(trans) #else void free_trans(transaction * trans) { if (trans) { free_trans(trans->chain); free(trans); } } #endif #ifdef RAW_FUNC int32_t real_commit_transaction(int32_t readonly) #else int32_t commit_transaction(context * ct, int32_t readonly) #endif { transaction *tmp_trans, *current; object * tmp_obj; int32_t idx,numaddparent; if (cur_transaction->parent) { rh_lock(cur_transaction->parent->lock); current = cur_transaction; while(current) { for (idx = 0; idx < current->num_cells; ++idx) { if (current->cells[idx].parent) { if (current->cells[idx].parent->local_version != current->cells[idx].orig_version) { rh_unlock(cur_transaction->parent->lock); return 0; } } else { if(find_obj_cell(cur_transaction->parent->chain, current->cells[idx].obj)) { rh_unlock(cur_transaction->parent->lock); return 0; } else numaddparent++; } } current = current->chain; } if (numaddparent) { #ifdef USE_GC tmp_trans = GC_malloc(sizeof(transaction)+(numaddparent - 1)*sizeof(trans_cell)); #else tmp_trans = malloc(sizeof(transaction)+(numaddparent - 1)*sizeof(trans_cell)); #endif tmp_trans->chain = cur_transaction->parent->chain; tmp_trans->num_cells = 0; cur_transaction->parent->chain = tmp_trans; } current = cur_transaction; while(current) { for (idx = 0; idx < cur_transaction->num_cells; ++idx) { if (cur_transaction->cells[idx].parent) { //Only commit a particular object if a change has been made if (cur_transaction->cells[idx].local_version) { tmp_obj = cur_transaction->cells[idx].parent->local_data; cur_transaction->cells[idx].parent->local_data = cur_transaction->cells[idx].local_data; release_ref(tmp_obj); cur_transaction->cells[idx].parent->local_version++; } else { release_ref(cur_transaction->cells[idx].local_data); } } else { memcpy(&(tmp_trans->cells[tmp_trans->num_cells++]), &(cur_transaction->cells[idx]), sizeof(trans_cell)); } } current = current->chain; } rh_unlock(cur_transaction->parent->lock); } else { if(readonly) { for (idx = 0; idx < cur_transaction->num_cells; ++idx) { release_ref(cur_transaction->cells[idx].local_data); } } else { rh_lock(trans_lock); current = cur_transaction; while(current) { for (idx = 0; idx < current->num_cells; ++idx) { if (current->cells[idx].obj->version != current->cells[idx].orig_version) { rh_unlock(trans_lock); return 0; } } current = current->chain; } current = cur_transaction; while(current) { for (idx = 0; idx < current->num_cells; ++idx) { //Only commit a particular object if a change has been made if (current->cells[idx].local_version) { tmp_obj = current->cells[idx].obj->data; current->cells[idx].obj->data = current->cells[idx].local_data; release_ref(tmp_obj); current->cells[idx].obj->version++; } else { release_ref(current->cells[idx].local_data); } } current = current->chain; } rh_unlock(trans_lock); } } rh_mutex_del(cur_transaction->lock); tmp_trans = cur_transaction->parent; free_trans(cur_transaction); cur_transaction = tmp_trans; return 1; } #ifdef RAW_FUNC void prep_retry() #else void prep_retry(context * ct) #endif { transaction * current; int32_t idx,got_global_lock=0; if (cur_transaction->parent) { rh_lock(cur_transaction->parent->lock); current = cur_transaction; while(current) { for (idx = 0; idx < current->num_cells; ++idx) { release_ref(current->cells[idx].local_data); current->cells[idx].local_version = 0; if (!current->cells[idx].parent) current->cells[idx].parent = find_obj_cell(cur_transaction->parent, current->cells[idx].obj); if (current->cells[idx].parent) { current->cells[idx].local_data = current->cells[idx].parent->local_data; current->cells[idx].orig_version = current->cells[idx].parent->local_version; } else { if (!got_global_lock) { rh_lock(trans_lock); got_global_lock = 1; } current->cells[idx].local_data = current->cells[idx].obj->data; current->cells[idx].orig_version = current->cells[idx].obj->version; } } current = current->chain; } if (got_global_lock) { rh_unlock(trans_lock); } rh_unlock(cur_transaction->parent->lock); } else { rh_lock(trans_lock); current = cur_transaction; while(current) { for (idx = 0; idx < current->num_cells; ++idx) { release_ref(current->cells[idx].local_data); current->cells[idx].local_version = 0; current->cells[idx].local_data = current->cells[idx].obj->data; current->cells[idx].orig_version = current->cells[idx].obj->version; } current = current->chain; } rh_unlock(trans_lock); } }