Browse Source

Fix race condition with #soa

gingerBill 1 year ago
parent
commit
d496dbf3a0
3 changed files with 24 additions and 15 deletions
  1. 2 4
      src/check_type.cpp
  2. 16 0
      src/threading.cpp
  3. 6 11
      src/types.cpp

+ 2 - 4
src/check_type.cpp

@@ -632,9 +632,6 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *
 	
 	
 	scope_reserve(ctx->scope, min_field_count);
 	scope_reserve(ctx->scope, min_field_count);
 
 
-	rw_mutex_lock(&struct_type->Struct.fields_mutex);
-	defer (rw_mutex_unlock(&struct_type->Struct.fields_mutex));
-
 	if (st->is_raw_union && min_field_count > 1) {
 	if (st->is_raw_union && min_field_count > 1) {
 		struct_type->Struct.is_raw_union = true;
 		struct_type->Struct.is_raw_union = true;
 		context = str_lit("struct #raw_union");
 		context = str_lit("struct #raw_union");
@@ -662,6 +659,7 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *
 			gb_unused(where_clause_ok);
 			gb_unused(where_clause_ok);
 		}
 		}
 		check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context);
 		check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context);
+		wait_signal_set(&struct_type->Struct.fields_wait_signal);
 	}
 	}
 
 
 #define ST_ALIGN(_name) if (st->_name != nullptr) {                                                \
 #define ST_ALIGN(_name) if (st->_name != nullptr) {                                                \
@@ -2553,8 +2551,8 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e
 		GB_ASSERT(is_type_struct(elem));
 		GB_ASSERT(is_type_struct(elem));
 
 
 		Type *old_struct = base_type(elem);
 		Type *old_struct = base_type(elem);
-		RW_MUTEX_GUARD(&old_struct->Struct.fields_mutex);
 
 
+		wait_signal_until_available(&old_struct->Struct.fields_wait_signal);
 		field_count = old_struct->Struct.fields.count;
 		field_count = old_struct->Struct.fields.count;
 
 
 		soa_struct = alloc_type_struct();
 		soa_struct = alloc_type_struct();

+ 16 - 0
src/threading.cpp

@@ -107,6 +107,22 @@ gb_internal void thread_set_name        (Thread *t, char const *name);
 gb_internal void yield_thread(void);
 gb_internal void yield_thread(void);
 gb_internal void yield_process(void);
 gb_internal void yield_process(void);
 
 
+struct Wait_Signal {
+	Futex futex;
+};
+
+gb_internal void wait_signal_until_available(Wait_Signal *ws) {
+	if (ws->futex.load() == 0) {
+		futex_wait(&ws->futex, 1);
+	}
+}
+
+gb_internal void wait_signal_set(Wait_Signal *ws) {
+	ws->futex.store(1);
+	futex_broadcast(&ws->futex);
+}
+
+
 
 
 struct MutexGuard {
 struct MutexGuard {
 	MutexGuard()                   = delete;
 	MutexGuard()                   = delete;

+ 6 - 11
src/types.cpp

@@ -144,7 +144,7 @@ struct TypeStruct {
 	Type *          soa_elem;
 	Type *          soa_elem;
 	i32             soa_count;
 	i32             soa_count;
 	StructSoaKind   soa_kind;
 	StructSoaKind   soa_kind;
-	RwMutex         fields_mutex;
+	Wait_Signal     fields_wait_signal;
 	BlockingMutex   offset_mutex; // for settings offsets
 	BlockingMutex   offset_mutex; // for settings offsets
 
 
 	bool            is_polymorphic;
 	bool            is_polymorphic;
@@ -2969,9 +2969,8 @@ gb_internal Selection lookup_field_from_index(Type *type, i64 index) {
 	isize max_count = 0;
 	isize max_count = 0;
 	switch (type->kind) {
 	switch (type->kind) {
 	case Type_Struct:
 	case Type_Struct:
-		rw_mutex_shared_lock(&type->Struct.fields_mutex);
+		wait_signal_until_available(&type->Struct.fields_wait_signal);
 		max_count = type->Struct.fields.count;
 		max_count = type->Struct.fields.count;
-		rw_mutex_shared_unlock(&type->Struct.fields_mutex);
 		break;
 		break;
 	case Type_Tuple:    max_count = type->Tuple.variables.count; break;
 	case Type_Tuple:    max_count = type->Tuple.variables.count; break;
 	}
 	}
@@ -2982,8 +2981,7 @@ gb_internal Selection lookup_field_from_index(Type *type, i64 index) {
 
 
 	switch (type->kind) {
 	switch (type->kind) {
 	case Type_Struct: {
 	case Type_Struct: {
-		rw_mutex_shared_lock(&type->Struct.fields_mutex);
-		defer (rw_mutex_shared_unlock(&type->Struct.fields_mutex));
+		wait_signal_until_available(&type->Struct.fields_wait_signal);
 		for (isize i = 0; i < max_count; i++) {
 		for (isize i = 0; i < max_count; i++) {
 			Entity *f = type->Struct.fields[i];
 			Entity *f = type->Struct.fields[i];
 			if (f->kind == Entity_Variable) {
 			if (f->kind == Entity_Variable) {
@@ -3048,9 +3046,8 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name
 				}
 				}
 			}
 			}
 			if (type->kind == Type_Struct) {
 			if (type->kind == Type_Struct) {
-				rw_mutex_shared_lock(&type->Struct.fields_mutex);
+				wait_signal_until_available(&type->Struct.fields_wait_signal);
 				isize field_count = type->Struct.fields.count;
 				isize field_count = type->Struct.fields.count;
-				rw_mutex_shared_unlock(&type->Struct.fields_mutex);
 				if (field_count != 0) for_array(i, type->Struct.fields) {
 				if (field_count != 0) for_array(i, type->Struct.fields) {
 					Entity *f = type->Struct.fields[i];
 					Entity *f = type->Struct.fields[i];
 					if (f->flags&EntityFlag_Using) {
 					if (f->flags&EntityFlag_Using) {
@@ -3079,9 +3076,8 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name
 		}
 		}
 
 
 		if (type->kind == Type_Struct) {
 		if (type->kind == Type_Struct) {
-			rw_mutex_shared_lock(&type->Struct.fields_mutex);
+			wait_signal_until_available(&type->Struct.fields_wait_signal);
 			Scope *s = type->Struct.scope;
 			Scope *s = type->Struct.scope;
-			rw_mutex_shared_unlock(&type->Struct.fields_mutex);
 			if (s != nullptr) {
 			if (s != nullptr) {
 				Entity *found = scope_lookup_current(s, field_name);
 				Entity *found = scope_lookup_current(s, field_name);
 				if (found != nullptr && found->kind != Entity_Variable) {
 				if (found != nullptr && found->kind != Entity_Variable) {
@@ -3129,9 +3125,8 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name
 			}
 			}
 		}
 		}
 
 
-		rw_mutex_shared_lock(&type->Struct.fields_mutex);
+		wait_signal_until_available(&type->Struct.fields_wait_signal);
 		isize field_count = type->Struct.fields.count;
 		isize field_count = type->Struct.fields.count;
-		rw_mutex_shared_unlock(&type->Struct.fields_mutex);
 		if (field_count != 0) for_array(i, type->Struct.fields) {
 		if (field_count != 0) for_array(i, type->Struct.fields) {
 			Entity *f = type->Struct.fields[i];
 			Entity *f = type->Struct.fields[i];
 			if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) {
 			if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) {