00001 /** \file barrier.c 00002 * \brief Write barriers. 00003 */ 00004 #include "internal.h" 00005 00006 /***************************************************************************/ 00007 /*! \defgroup write_barrier_hook Write Barrier: Hook */ 00008 /*@{*/ 00009 00010 /** 00011 * Write barrier hook for a "pure pointer". 00012 * A "pure pointer" must point to beginning of tm_alloc()'ed address. 00013 * A pure pointer should never be 0. 00014 */ 00015 void (*_tm_write_barrier_pure)(void *referent) = __tm_write_barrier_ignore; 00016 00017 /** 00018 * Write barrier hook for pointer into stack or data segment. 00019 */ 00020 void (*_tm_write_barrier_root)(void *referent) = __tm_write_barrier_ignore; 00021 00022 /** 00023 * Write barrier hook for unknown pointer. 00024 * Pointer may be in stack, data segment or within tm_alloc() node. 00025 * Pointer may be 0. 00026 */ 00027 void (*_tm_write_barrier)(void *referent) = __tm_write_barrier_ignore; 00028 00029 /*@}*/ 00030 00031 00032 /*******************************************************************************/ 00033 /*! \defgroup write_barrier_function Write Barrier: Function */ 00034 /*@{*/ 00035 00036 /** 00037 * Must be called after any ptrs 00038 * within the tm_node n are mutated. 00039 */ 00040 static __inline 00041 void tm_write_barrier_node(tm_node *n) 00042 { 00043 switch ( tm_node_color(n) ) { 00044 case tm_ECRU: 00045 /** 00046 * If node is tm_ECRU, 00047 * It has not been reached yet. 00048 */ 00049 break; 00050 00051 case tm_GREY: 00052 /** 00053 * If node is tm_GREY, 00054 * it is already marked for scanning. 00055 */ 00056 00057 /** 00058 * If this node is already being scanned, 00059 * resume scanning on another node. 00060 * 00061 * This should be very rare. 00062 * 00063 * See _tm_node_scan_some(). 00064 */ 00065 if ( tm.node_color_iter[tm_GREY].scan_node == n ) { 00066 // tm_abort(); 00067 #if 0 00068 fprintf(stderr, "*"); 00069 fflush(stderr); 00070 #endif 00071 tm.trigger_full_gc = 1; 00072 } 00073 break; 00074 00075 case tm_BLACK: 00076 /** 00077 * If node is tm_BLACK, 00078 * The node has already been marked and scanned. 00079 * The mutator may have introduced new pointers 00080 * to ECRU nodes. 00081 * 00082 * Reschedule it to be scanned. 00083 */ 00084 #if tm_TIME_STAT 00085 tm_time_stat_begin(&tm.ts_barrier_black); 00086 #endif 00087 00088 tm_node_set_color(n, tm_node_to_block(n), tm_GREY); 00089 00090 #if 0 00091 fprintf(stderr, "G"); 00092 fflush(stderr); 00093 #endif 00094 00095 #if tm_TIME_STAT 00096 tm_time_stat_end(&tm.ts_barrier_black); 00097 #endif 00098 #if 0 00099 tm_msg("w b n%p\n", n); 00100 #endif 00101 break; 00102 00103 default: 00104 tm_abort(); 00105 break; 00106 } 00107 } 00108 00109 00110 /** 00111 * Write barrier for nothing. 00112 * 00113 * DO NOTHING 00114 */ 00115 void __tm_write_barrier_ignore(void *ptr) 00116 { 00117 } 00118 00119 /*@}*/ 00120 00121 /*******************************************************************************/ 00122 /*! \defgroup write_barrier_pure Write Barrier: Pure */ 00123 /*@{*/ 00124 00125 /** 00126 * Write barrier for pure pointers during tm_SCAN. 00127 */ 00128 void __tm_write_barrier_pure(void *ptr) 00129 { 00130 /*! Begin time stats. */ 00131 #if tm_TIME_STAT 00132 tm_time_stat_begin(&tm.ts_barrier_pure); 00133 #endif 00134 00135 tm_write_barrier_node(tm_pure_ptr_to_node(ptr)); 00136 00137 /*! End time stats. */ 00138 #if tm_TIME_STAT 00139 tm_time_stat_end(&tm.ts_barrier_pure); 00140 #endif 00141 } 00142 00143 00144 /*@}*/ 00145 00146 00147 #define RETURN goto _return 00148 00149 /*******************************************************************************/ 00150 /*! \defgroup write_barrier_root Write Barrier: Root */ 00151 /*@{*/ 00152 00153 00154 /** 00155 * Write barrier for root or stack pointers. 00156 * 00157 * Don't know if this root has been marked yet or not. 00158 */ 00159 void __tm_write_barrier_root(void *ptr) 00160 { 00161 /*! Begin time stats. */ 00162 #if tm_TIME_STAT 00163 tm_time_stat_begin(&tm.ts_barrier_root); 00164 #endif 00165 00166 /** 00167 * If the ptr is a reference to a stack allocated object, 00168 * do nothing, because the stack will be scanned atomically before 00169 * the sweep phase. 00170 */ 00171 if ( (void*) &ptr <= ptr && ptr <= tm.roots[1].h ) { 00172 ++ tm.stack_mutations; 00173 #if 0 00174 tm_msg("w s p%p\n", ptr); 00175 #endif 00176 RETURN; 00177 } 00178 00179 /** 00180 * Otherwise, 00181 * If the ptr is a reference to the heap. 00182 * Do nothing, because we haven't started marking yet. 00183 */ 00184 #if 1 00185 if ( _tm_page_in_use(ptr) ) 00186 RETURN; 00187 #else 00188 if ( tm_ptr_l <= ptr && ptr <= tm_ptr_h ) 00189 RETURN; 00190 #endif 00191 00192 /** 00193 * Otherwise, ptr must be a pointer to statically allocated (root) object. 00194 * Mark the roots as being mutated. 00195 */ 00196 ++ tm.data_mutations; 00197 #if 0 00198 tm_msg("w r p%p\n", ptr); 00199 #endif 00200 00201 _return: 00202 (void) 0; 00203 00204 /*! End time stats. */ 00205 #if tm_TIME_STAT 00206 tm_time_stat_end(&tm.ts_barrier_root); 00207 #endif 00208 } 00209 00210 00211 /*@}*/ 00212 00213 00214 00215 /*******************************************************************************/ 00216 /*! \defgroup write_barrier_general Write Barrier: General */ 00217 /*@{*/ 00218 00219 00220 /** 00221 * Write barrier for general references. 00222 */ 00223 void __tm_write_barrier(void *ptr) 00224 { 00225 tm_node *n; 00226 00227 /*! Begin time stats. */ 00228 #if tm_TIME_STAT 00229 tm_time_stat_begin(&tm.ts_barrier); 00230 #endif 00231 00232 /** 00233 * If the ptr is a reference to a stack allocated object, 00234 * do nothing, because the stack will be marked before 00235 * the sweep phase. 00236 */ 00237 if ( (void*) &ptr <= ptr && ptr <= tm.roots[1].h ) { 00238 ++ tm.stack_mutations; 00239 // tm_msg("w s p%p\n", ptr); 00240 RETURN; 00241 } 00242 00243 /** 00244 * Otherwise, 00245 * if the ptr is a reference to a node, 00246 * schedule it for remarking if it has already been marked. 00247 * 00248 * If it is not a reference to a node, 00249 * It must be a reference to a statically allocated object. 00250 * This means the data root set has (probably) been mutated. 00251 * Must flag the roots for remarking before the sweep phase. 00252 */ 00253 if ( (n = tm_ptr_to_node(ptr)) ) { 00254 tm_write_barrier_node(n); 00255 } else { 00256 ++ tm.data_mutations; 00257 #if 0 00258 tm_msg("w r p%p\n", ptr); 00259 #endif 00260 } 00261 00262 _return: 00263 (void) 0; 00264 00265 /*! End time stats. */ 00266 #if tm_TIME_STAT 00267 tm_time_stat_end(&tm.ts_barrier); 00268 #endif 00269 } 00270 00271 00272 /*@}*/ 00273