|
| 1 | +#include "ross.h" |
| 2 | + |
| 3 | +// Defining simple linked list because we don't care about speed at |
| 4 | +// initialization for SEQUENTIAL_ROLLBACK_CHECK |
| 5 | +struct llist_chptr { |
| 6 | + crv_checkpointer * val; |
| 7 | + struct llist_chptr * next; |
| 8 | +}; |
| 9 | +struct llist_chptr * head_linked_list = NULL; |
| 10 | +struct llist_chptr * tail_linked_list = NULL; |
| 11 | + |
| 12 | +struct crv_checkpointer ** checkpointer_for_lps = NULL; |
| 13 | + |
| 14 | +void crv_add_custom_state_checkpoint(crv_checkpointer * state_checkpoint) { |
| 15 | + struct llist_chptr * next = malloc(sizeof(struct llist_chptr)); |
| 16 | + if (next == NULL) { |
| 17 | + tw_error(TW_LOC, "Could not allocate memory"); |
| 18 | + } |
| 19 | + next->val = state_checkpoint; |
| 20 | + next->next = NULL; |
| 21 | + |
| 22 | + if (head_linked_list == NULL) { |
| 23 | + tail_linked_list = head_linked_list = next; |
| 24 | + } else { |
| 25 | + tail_linked_list->next = next; |
| 26 | + tail_linked_list = next; |
| 27 | + } |
| 28 | +} |
| 29 | + |
| 30 | +static void crv_clean_linkedlist(void) { |
| 31 | + if (head_linked_list == NULL) { |
| 32 | + return; |
| 33 | + } |
| 34 | + |
| 35 | + struct llist_chptr * prev = head_linked_list; |
| 36 | + struct llist_chptr * iter = prev->next; |
| 37 | + while (iter != NULL) { |
| 38 | + free(prev); |
| 39 | + prev = iter; |
| 40 | + iter = iter->next; |
| 41 | + } |
| 42 | + free(tail_linked_list); |
| 43 | + head_linked_list = NULL; |
| 44 | + tail_linked_list = NULL; |
| 45 | +} |
| 46 | + |
| 47 | +size_t crv_init_checkpoints(void) { |
| 48 | + // No need to construct array with crv_checkpointer's if there isn't any |
| 49 | + if (head_linked_list == NULL) { |
| 50 | + return 0; |
| 51 | + } |
| 52 | + |
| 53 | + checkpointer_for_lps = malloc(g_tw_nlp * sizeof(struct crv_checkpointer *)); |
| 54 | + |
| 55 | + size_t largest_lp_checkpoint = 0; |
| 56 | + for (size_t i = 0; i < g_tw_nlp; i++) { |
| 57 | + tw_lp * lp = g_tw_lp[i]; |
| 58 | + struct crv_checkpointer * state_checkpointer = NULL; |
| 59 | + |
| 60 | + // Finding crv_checkpointer, if it exists, for current lp |
| 61 | + for (struct llist_chptr * iter = head_linked_list; iter != NULL; iter = iter->next) { |
| 62 | + if (lp->type == iter->val->lptype) { |
| 63 | + state_checkpointer = iter->val; |
| 64 | + break; |
| 65 | + } |
| 66 | + } |
| 67 | + |
| 68 | + checkpointer_for_lps[i] = state_checkpointer; |
| 69 | + |
| 70 | + if (state_checkpointer != NULL && state_checkpointer->sz_storage > largest_lp_checkpoint) { |
| 71 | + largest_lp_checkpoint = state_checkpointer->sz_storage; |
| 72 | + } |
| 73 | + |
| 74 | + } |
| 75 | + |
| 76 | + crv_clean_linkedlist(); |
| 77 | + |
| 78 | + return largest_lp_checkpoint; |
| 79 | +} |
| 80 | + |
| 81 | +static crv_checkpointer * get_chkpntr(tw_lpid id) { |
| 82 | + if (checkpointer_for_lps == NULL) { |
| 83 | + return NULL; |
| 84 | + } |
| 85 | + return checkpointer_for_lps[id]; |
| 86 | +} |
| 87 | + |
| 88 | +static void print_event(crv_checkpointer const * chkptr, tw_lp * clp, tw_event * cev) { |
| 89 | + fprintf(stderr, "\n Event:\n ---------\n"); |
| 90 | + fprintf(stderr, " Bit field contents\n"); |
| 91 | + tw_bf b = cev->cv; |
| 92 | + fprintf(stderr, " c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15\n"); |
| 93 | + fprintf(stderr, " %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d \n", b.c0, b.c1, b.c2, b.c3, b.c4, b.c5, b.c6, b.c7, b.c8, b.c9, b.c10, b.c11, b.c12, b.c13, b.c14, b.c15); |
| 94 | + fprintf(stderr, " c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31\n"); |
| 95 | + fprintf(stderr, " %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d \n", b.c16, b.c17, b.c18, b.c19, b.c20, b.c21, b.c22, b.c23, b.c24, b.c25, b.c26, b.c27, b.c28, b.c29, b.c30, b.c31); |
| 96 | + fprintf(stderr, " ---------\n Event contents\n"); |
| 97 | + tw_fprint_binary_array(stderr, "", tw_event_data(cev), g_tw_msg_sz); |
| 98 | + if (chkptr && chkptr->print_event) { |
| 99 | + fprintf(stderr, "---------------------------------\n"); |
| 100 | + chkptr->print_event(stderr, "", clp->cur_state, tw_event_data(cev)); |
| 101 | + } |
| 102 | + fprintf(stderr, "---------------------------------\n"); |
| 103 | +} |
| 104 | + |
| 105 | +void crv_check_lpstates( |
| 106 | + tw_lp * clp, |
| 107 | + tw_event * cev, |
| 108 | + crv_lpstate_checkpoint_internal const * before_state, |
| 109 | + char const * before_msg, |
| 110 | + char const * after_msg |
| 111 | +) { |
| 112 | + crv_checkpointer const * chkptr = get_chkpntr(clp->id); |
| 113 | + |
| 114 | + bool state_equal; |
| 115 | + if (chkptr && chkptr->check_lps) { |
| 116 | + state_equal = chkptr->check_lps(before_state->state, clp->cur_state); |
| 117 | + } else { |
| 118 | + state_equal = !memcmp(before_state->state, clp->cur_state, clp->type->state_sz); |
| 119 | + } |
| 120 | + |
| 121 | + if (!state_equal) { |
| 122 | + fprintf(stderr, "Error found by a rollback of an event\n"); |
| 123 | + fprintf(stderr, " The state of the LP is not consistent when rollbacking!\n"); |
| 124 | + fprintf(stderr, " LPID = %lu\n", clp->gid); |
| 125 | + fprintf(stderr, "\n LP contents (%s):\n", before_msg); |
| 126 | + tw_fprint_binary_array(stderr, "", before_state->state, clp->type->state_sz); |
| 127 | + if (chkptr && chkptr->print_checkpoint) { |
| 128 | + fprintf(stderr, "---------------------------------\n"); |
| 129 | + chkptr->print_checkpoint(stderr, "", before_state->state); |
| 130 | + fprintf(stderr, "---------------------------------\n"); |
| 131 | + } |
| 132 | + fprintf(stderr, "\n LP contents (%s):\n", after_msg); |
| 133 | + tw_fprint_binary_array(stderr, "", clp->cur_state, clp->type->state_sz); |
| 134 | + if (chkptr && chkptr->print_lp) { |
| 135 | + fprintf(stderr, "---------------------------------\n"); |
| 136 | + chkptr->print_lp(stderr, "", clp->cur_state); |
| 137 | + fprintf(stderr, "---------------------------------\n"); |
| 138 | + } |
| 139 | + print_event(chkptr, clp, cev); |
| 140 | + tw_net_abort(); |
| 141 | + } |
| 142 | + if (memcmp(&before_state->rng, clp->rng, sizeof(struct tw_rng_stream))) { |
| 143 | + fprintf(stderr, "Error found by rollback of an event\n"); |
| 144 | + fprintf(stderr, " Random number generation `rng` did not rollback properly!\n"); |
| 145 | + fprintf(stderr, " This often happens if the random number generation was not properly rollbacked by the reverse handler!\n"); |
| 146 | + fprintf(stderr, " LPID = %lu\n", clp->gid); |
| 147 | + fprintf(stderr, "\n rng contents (%s):\n", before_msg); |
| 148 | + tw_fprint_binary_array(stderr, "", &before_state->rng, sizeof(struct tw_rng_stream)); |
| 149 | + fprintf(stderr, "\n rng contents (%s):\n", after_msg); |
| 150 | + tw_fprint_binary_array(stderr, "", clp->rng, sizeof(struct tw_rng_stream)); |
| 151 | + print_event(chkptr, clp, cev); |
| 152 | + tw_net_abort(); |
| 153 | + } |
| 154 | + if (memcmp(&before_state->core_rng, clp->core_rng, sizeof(struct tw_rng_stream))) { |
| 155 | + fprintf(stderr, "Error found by rollback of an event\n"); |
| 156 | + fprintf(stderr, " Random number generation `core_rng` did not rollback properly!\n"); |
| 157 | + fprintf(stderr, " LPID = %lu\n", clp->gid); |
| 158 | + fprintf(stderr, "\n core_rng contents (%s):\n", before_msg); |
| 159 | + tw_fprint_binary_array(stderr, "", &before_state->core_rng, sizeof(struct tw_rng_stream)); |
| 160 | + fprintf(stderr, "\n core_rng contents (%s):\n", after_msg); |
| 161 | + tw_fprint_binary_array(stderr, "", clp->core_rng, sizeof(struct tw_rng_stream)); |
| 162 | + print_event(chkptr, clp, cev); |
| 163 | + tw_net_abort(); |
| 164 | + } |
| 165 | + if (before_state->triggered_gvt_hook != clp->triggered_gvt_hook) { |
| 166 | + fprintf(stderr, "Error found by rollback of an event\n"); |
| 167 | + fprintf(stderr, " triggered_gvt_hook incogruent value, this is most likely the result of not calling tw_trigger_gvt_hook_now_rev when rollbacking tw_trigger_gvt_hook_now!\n"); |
| 168 | + fprintf(stderr, " LPID = %lu\n", clp->gid); |
| 169 | + fprintf(stderr, "\n lp->triggered_gvt_hook (%s) = %d\n", before_msg, before_state->triggered_gvt_hook); |
| 170 | + fprintf(stderr, "\n lp->triggered_gvt_hook contents (%s) = %d\n", after_msg, clp->triggered_gvt_hook); |
| 171 | + print_event(chkptr, clp, cev); |
| 172 | + tw_net_abort(); |
| 173 | + } |
| 174 | +} |
| 175 | + |
| 176 | +void crv_copy_lpstate(crv_lpstate_checkpoint_internal * into, tw_lp const * clp) { |
| 177 | + crv_checkpointer const * chkptr = get_chkpntr(clp->id); |
| 178 | + |
| 179 | + if (chkptr && chkptr->save_lp) { |
| 180 | + chkptr->save_lp(into->state, clp->cur_state); |
| 181 | + } else { |
| 182 | + memcpy(into->state, clp->cur_state, clp->type->state_sz); |
| 183 | + } |
| 184 | + memcpy(&into->rng, clp->rng, sizeof(struct tw_rng_stream)); |
| 185 | + memcpy(&into->core_rng, clp->core_rng, sizeof(struct tw_rng_stream)); |
| 186 | + into->triggered_gvt_hook = clp->triggered_gvt_hook; |
| 187 | +} |
| 188 | + |
| 189 | +void crv_clean_lpstate(crv_lpstate_checkpoint_internal * state, tw_lp const * clp) { |
| 190 | + crv_checkpointer const * chkptr = get_chkpntr(clp->id); |
| 191 | + |
| 192 | + if (chkptr && chkptr->clean_lp) { |
| 193 | + chkptr->clean_lp(state->state); |
| 194 | + } |
| 195 | +} |
0 commit comments