Skip to content

Commit e5be6e6

Browse files
Kimeek42gangatp
authored andcommitted
Add c++ binding/implementation thread safety options
1 parent 6248dcf commit e5be6e6

File tree

4 files changed

+256
-25
lines changed

4 files changed

+256
-25
lines changed

Source/automaticcomponenttoolkit.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ func printUsageInfo() {
585585
}
586586

587587
func main() {
588-
ACTVersion := "1.8.0-develop"
588+
ACTVersion := "1.8.1-develop"
589589
fmt.Fprintln(os.Stdout, "Automatic Component Toolkit v"+ACTVersion)
590590
if len(os.Args) < 2 {
591591
printUsageInfo()
@@ -690,6 +690,11 @@ func main() {
690690
log.Fatal(err)
691691
}
692692

693+
addExtraBaseClassMethods := component.addExtraBaseClassMethods()
694+
if addExtraBaseClassMethods != nil {
695+
log.Printf("%s", *addExtraBaseClassMethods)
696+
}
697+
693698
if mode == eACTModeDiff {
694699
log.Printf("Loading Component Description File to compare to")
695700
componentB, err := ReadComponentDefinition(diffFile, ACTVersion)

Source/buildbindingccpp.go

Lines changed: 86 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@ func writeDynamicCPPMethodDeclaration(method ComponentDefinitionMethod, w Langua
591591
}
592592

593593
func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassIdentifier string, ClassName string,
594-
implementationLines []string, isGlobal bool, includeComments bool, doNotThrow bool, useCPPTypes bool, ExplicitLinking bool, forWASM bool) error {
594+
implementationLines []string, isGlobal bool, includeComments bool, doNotThrow bool, useCPPTypes bool, ExplicitLinking bool, forWASM bool, multiThreadedEnv bool, classThreadSafetyOption ThreadSafetyOption) error {
595595

596596
WASMPrefix := ""
597597
WASMCast := ""
@@ -616,6 +616,14 @@ func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, N
616616
checkErrorCodeEnd := ")"
617617
makeSharedParameter := ""
618618

619+
if multiThreadedEnv && !isGlobal {
620+
if classThreadSafetyOption == eThreadSafetyStrict {
621+
checkErrorCodeEnd = ", true)"
622+
} else {
623+
checkErrorCodeEnd = ", false)"
624+
}
625+
}
626+
619627
if isGlobal {
620628
if ExplicitLinking {
621629
CMethodName = fmt.Sprintf("m_WrapperTable.m_%s", method.MethodName)
@@ -858,6 +866,12 @@ func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, N
858866
initCallParameters = initCallParameters + initCallParameter
859867
}
860868

869+
addThreadSafeCalls := multiThreadedEnv && !isGlobal && ((classThreadSafetyOption == eThreadSafetySoft && requiresInitCall) || classThreadSafetyOption == eThreadSafetyStrict)
870+
871+
if addThreadSafeCalls {
872+
checkErrorCodeEnd = ", true)"
873+
}
874+
861875
w.Writeln(" ")
862876
if includeComments {
863877
w.Writeln(" /**")
@@ -876,6 +890,11 @@ func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, N
876890

877891
w.Writeln(" {")
878892
w.Writelns(" ", definitionCodeLines)
893+
894+
if addThreadSafeCalls {
895+
w.Writeln(" %s();", getLockInstanceMethodName())
896+
}
897+
879898
if requiresInitCall {
880899
w.Writeln(" %s%s(%s)%s;", checkErrorCodeBegin, CMethodName, initCallParameters, checkErrorCodeEnd)
881900
}
@@ -888,6 +907,10 @@ func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, N
888907
w.Writelns(" ", implementationLines)
889908
}
890909

910+
if addThreadSafeCalls {
911+
w.Writeln(" %s();", getUnlockInstanceMethodName())
912+
}
913+
891914
if len(returnCodeLines) > 0 {
892915
w.Writeln(" ")
893916
w.Writelns(" ", returnCodeLines)
@@ -905,11 +928,20 @@ func writeDynamicCppBaseClassMethods(component ComponentDefinition, baseClass Co
905928
w.Writeln(" /* Handle to Instance in library*/")
906929
w.Writeln(" %sHandle m_pHandle;", NameSpace)
907930
w.Writeln("")
908-
w.Writeln(" /* Checks for an Error code and raises Exceptions */")
909-
w.Writeln(" void CheckError(%sResult nResult)", NameSpace)
931+
if component.isMultiThreadedEnv() {
932+
w.Writeln(" /* Checks for an Error code, raises Exceptions and unlocks library object*/")
933+
w.Writeln(" void CheckError(%sResult nResult, bool unlockIfError)", NameSpace)
934+
} else {
935+
w.Writeln(" /* Checks for an Error code and raises Exceptions */")
936+
w.Writeln(" void CheckError(%sResult nResult)", NameSpace)
937+
}
910938
w.Writeln(" {")
911939
w.Writeln(" if (m_pWrapper != nullptr)")
912-
w.Writeln(" m_pWrapper->CheckError(this, nResult);")
940+
if component.isMultiThreadedEnv() {
941+
w.Writeln(" m_pWrapper->CheckError(this, nResult, unlockIfError);")
942+
} else {
943+
w.Writeln(" m_pWrapper->CheckError(this, nResult);")
944+
}
913945
w.Writeln(" }")
914946
w.Writeln("public:")
915947
w.Writeln(" /**")
@@ -1390,19 +1422,42 @@ func writeClassDeclarations(w LanguageWriter, component ComponentDefinition, cpp
13901422
w.Writeln(" {")
13911423
w.Writeln(" }")
13921424
w.Writeln(" ")
1425+
1426+
for _, method := range class.Methods {
1427+
err := writeDynamicCPPMethodDeclaration(method, w, NameSpace, ClassIdentifier, cppClassName)
1428+
if err != nil {
1429+
return err
1430+
}
1431+
}
1432+
13931433
} else {
13941434
err := writeDynamicCppBaseClassMethods(component, baseClass, w, NameSpace, BaseName, cppClassPrefix, ClassIdentifier)
13951435
if err != nil {
13961436
return err
13971437
}
1398-
}
13991438

1400-
for _, method := range class.Methods {
1401-
err := writeDynamicCPPMethodDeclaration(method, w, NameSpace, ClassIdentifier, cppClassName)
1402-
if err != nil {
1403-
return err
1439+
extraBaseClassMethods := []ComponentDefinitionMethod{}
1440+
for _, method := range class.Methods {
1441+
if method.isExtraBaseClassmethod() {
1442+
extraBaseClassMethods = append(extraBaseClassMethods, method)
1443+
} else {
1444+
err := writeDynamicCPPMethodDeclaration(method, w, NameSpace, ClassIdentifier, cppClassName)
1445+
if err != nil {
1446+
return err
1447+
}
1448+
}
1449+
}
1450+
1451+
w.Writeln(" ")
1452+
w.Writeln("protected:")
1453+
for _, method := range extraBaseClassMethods {
1454+
err := writeDynamicCPPMethodDeclaration(method, w, NameSpace, ClassIdentifier, cppClassName)
1455+
if err != nil {
1456+
return err
1457+
}
14041458
}
14051459
}
1460+
14061461
w.Writeln("};")
14071462
}
14081463
return nil
@@ -1450,13 +1505,22 @@ func writePolymorphicFactoryImplementation(w LanguageWriter, component Component
14501505
w.Writeln("}")
14511506
}
14521507

1453-
func writeCheckErrorImplementation(w LanguageWriter, ErrorMethodName string, ClassIdentifier string, cppBaseClassName string, NameSpace string) {
1454-
w.Writeln(" inline void C%sWrapper::CheckError(%s * pBaseClass, %sResult nResult)", ClassIdentifier, cppBaseClassName, NameSpace)
1508+
func writeCheckErrorImplementation(w LanguageWriter, ErrorMethodName string, ClassIdentifier string, cppBaseClassName string, NameSpace string, multiThreadedEnv bool) {
1509+
if multiThreadedEnv {
1510+
w.Writeln(" inline void C%sWrapper::CheckError(%s * pBaseClass, %sResult nResult, bool unlockIfError)", ClassIdentifier, cppBaseClassName, NameSpace)
1511+
} else {
1512+
w.Writeln(" inline void C%sWrapper::CheckError(%s * pBaseClass, %sResult nResult)", ClassIdentifier, cppBaseClassName, NameSpace)
1513+
}
14551514
w.Writeln(" {")
14561515
w.Writeln(" if (nResult != 0) {")
14571516
w.Writeln(" std::string sErrorMessage;")
14581517
w.Writeln(" if (pBaseClass != nullptr) {")
14591518
w.Writeln(" %s(pBaseClass, sErrorMessage);", ErrorMethodName)
1519+
if multiThreadedEnv {
1520+
w.Writeln(" if (unlockIfError) {")
1521+
w.Writeln(" pBaseClass->%s();", getUnlockInstanceMethodName())
1522+
w.Writeln(" }")
1523+
}
14601524
w.Writeln(" }")
14611525
w.Writeln(" throw E%sException(nResult, sErrorMessage);", NameSpace)
14621526
w.Writeln(" }")
@@ -1539,7 +1603,11 @@ func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace s
15391603
writeWrapperLifeTimeHandling(w, cppClassPrefix, ClassIdentifier, ExplicitLinking)
15401604

15411605
w.Writeln(" ")
1542-
w.Writeln(" inline void CheckError(%s * pBaseClass, %sResult nResult);", cppBaseClassName, NameSpace)
1606+
if component.isMultiThreadedEnv() {
1607+
w.Writeln(" inline void CheckError(%s * pBaseClass, %sResult nResult, bool unlockIfError = false);", cppBaseClassName, NameSpace)
1608+
} else {
1609+
w.Writeln(" inline void CheckError(%s * pBaseClass, %sResult nResult);", cppBaseClassName, NameSpace)
1610+
}
15431611
w.Writeln("")
15441612

15451613
for j := 0; j < len(global.Methods); j++ {
@@ -1622,15 +1690,15 @@ func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace s
16221690
implementationLines = append(implementationLines, fmt.Sprintf(" throw E%sException(%s_ERROR_COULDNOTLOADLIBRARY, \"Unknown namespace \" + %s);", NameSpace, strings.ToUpper(NameSpace), sParamName))
16231691
}
16241692

1625-
err = writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, "Wrapper", implementationLines, true, true, false, useCPPTypes, ExplicitLinking, false)
1693+
err = writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, "Wrapper", implementationLines, true, true, false, useCPPTypes, ExplicitLinking, false, component.isMultiThreadedEnv(), eThreadSafetyNone)
16261694
if err != nil {
16271695
return err
16281696
}
16291697

16301698
}
16311699

16321700
w.Writeln("")
1633-
writeCheckErrorImplementation(w, component.Global.ErrorMethod, ClassIdentifier, cppBaseClassName, NameSpace)
1701+
writeCheckErrorImplementation(w, component.Global.ErrorMethod, ClassIdentifier, cppBaseClassName, NameSpace, component.isMultiThreadedEnv())
16341702
w.Writeln("")
16351703

16361704
if ExplicitLinking {
@@ -1648,7 +1716,7 @@ func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace s
16481716
w.Writeln(" */")
16491717
for j := 0; j < len(class.Methods); j++ {
16501718
method := class.Methods[j]
1651-
err := writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, class.ClassName, make([]string, 0), false, true, false, useCPPTypes, ExplicitLinking, false)
1719+
err := writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, class.ClassName, make([]string, 0), false, true, false, useCPPTypes, ExplicitLinking, false, component.isMultiThreadedEnv(), class.eThreadSafetyOption())
16521720
if err != nil {
16531721
return err
16541722
}
@@ -2217,14 +2285,14 @@ func buildCppwasmGuestHeader(component ComponentDefinition, w LanguageWriter, Na
22172285
implementationLines = append(implementationLines, fmt.Sprintf(" throw E%sException(%s_ERROR_COULDNOTLOADLIBRARY, \"Unknown namespace \" + %s);", NameSpace, strings.ToUpper(NameSpace), sParamName))
22182286
}
22192287

2220-
err = writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, "Wrapper", implementationLines, true, true, false, useCPPTypes, ExplicitLinking, true)
2288+
err = writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, "Wrapper", implementationLines, true, true, false, useCPPTypes, ExplicitLinking, true, false, eThreadSafetyNone)
22212289
if err != nil {
22222290
return err
22232291
}
22242292
}
22252293

22262294
w.Writeln("")
2227-
writeCheckErrorImplementation(w, component.Global.ErrorMethod, ClassIdentifier, cppBaseClassName, NameSpace)
2295+
writeCheckErrorImplementation(w, component.Global.ErrorMethod, ClassIdentifier, cppBaseClassName, NameSpace, false)
22282296
w.Writeln("")
22292297

22302298
for i := 0; i < len(component.Classes); i++ {
@@ -2236,7 +2304,7 @@ func buildCppwasmGuestHeader(component ComponentDefinition, w LanguageWriter, Na
22362304
w.Writeln(" */")
22372305
for j := 0; j < len(class.Methods); j++ {
22382306
method := class.Methods[j]
2239-
err := writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, class.ClassName, make([]string, 0), false, true, false, useCPPTypes, ExplicitLinking, true)
2307+
err := writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, class.ClassName, make([]string, 0), false, true, false, useCPPTypes, ExplicitLinking, true, false, eThreadSafetyNone)
22402308
if err != nil {
22412309
return err
22422310
}

Source/buildimplementationcpp.go

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,39 @@ func writeSharedPtrTemplate(component ComponentDefinition, w LanguageWriter, Cla
314314
w.Writeln("")
315315
}
316316

317+
func getWithMutexClassName(ClassIdentifier string, ClassName string) (string) {
318+
return ClassIdentifier + ClassName + "WithMutex"
319+
}
320+
321+
func writeBaseInterfaceWithMutexClass(baseClass ComponentDefinitionClass, w LanguageWriter, ClassIdentifier string) {
322+
baseClassName:= "I" + baseClass.ClassName
323+
className := "I" + getWithMutexClassName(ClassIdentifier, baseClass.ClassName)
324+
lockInstanceMethod := LockInstanceMethod()
325+
unlockInstanceMethod := UnlockInstanceMethod()
326+
327+
w.Writeln("")
328+
w.Writeln("/**")
329+
w.Writeln(" Definition of a class with mutex for %s", baseClassName)
330+
w.Writeln("*/")
331+
w.Writeln("class %s : public virtual %s", className, baseClassName)
332+
w.Writeln("{")
333+
w.Writeln("private:")
334+
w.Writeln(" std::mutex m_mutex;")
335+
w.Writeln("public:")
336+
w.Writeln("")
337+
w.Writeln(" /**")
338+
w.Writeln(" * %s::%s - %s", className, lockInstanceMethod.MethodName, lockInstanceMethod.MethodDescription)
339+
w.Writeln(" */")
340+
w.Writeln(" virtual void %s() { m_mutex.lock(); }", lockInstanceMethod.MethodName)
341+
w.Writeln("")
342+
w.Writeln(" /**")
343+
w.Writeln(" * %s::%s - %s", className, unlockInstanceMethod.MethodName, unlockInstanceMethod.MethodDescription)
344+
w.Writeln(" */")
345+
w.Writeln(" virtual void %s() { m_mutex.unlock();}", unlockInstanceMethod.MethodName)
346+
w.Writeln("};")
347+
w.Writeln("")
348+
}
349+
317350
func writeCPPClassInterface(component ComponentDefinition, class ComponentDefinitionClass, w LanguageWriter, NameSpace string, NameSpaceImplementation string, ClassIdentifier string, BaseName string) (error) {
318351
w.Writeln("")
319352
w.Writeln("/*************************************************************************************************************************")
@@ -324,7 +357,11 @@ func writeCPPClassInterface(component ComponentDefinition, class ComponentDefini
324357
if (!component.isBaseClass(class)) {
325358
parentClassString = " : public virtual "
326359
if (class.ParentClass == "") {
327-
parentClassString += fmt.Sprintf("I%s%s ", ClassIdentifier, component.Global.BaseClassName)
360+
if (class.isThreadSafe()) {
361+
parentClassString += fmt.Sprintf("I%s ", getWithMutexClassName(ClassIdentifier, component.Global.BaseClassName))
362+
} else {
363+
parentClassString += fmt.Sprintf("I%s%s ", ClassIdentifier, component.Global.BaseClassName)
364+
}
328365
} else {
329366
parentClassString += fmt.Sprintf("I%s%s ", ClassIdentifier, class.ParentClass)
330367
}
@@ -334,9 +371,8 @@ func writeCPPClassInterface(component ComponentDefinition, class ComponentDefini
334371
w.Writeln("class %s%s{", classInterfaceName, parentClassString)
335372

336373
if (component.isStringOutBaseClass(class)) {
337-
w.Writeln("private:")
338-
w.Writeln(" std::unique_ptr<ParameterCache> m_ParameterCache;")
339-
374+
w.Writeln("protected:")
375+
w.Writeln(" std::unique_ptr<ParameterCache> m_ParameterCache;")
340376
}
341377

342378
w.Writeln("public:")
@@ -411,7 +447,23 @@ func writeCPPClassInterface(component ComponentDefinition, class ComponentDefini
411447
w.Writeln(" {")
412448
w.Writeln(" return m_ParameterCache.get();")
413449
w.Writeln(" }")
414-
w.Writeln("")
450+
w.Writeln("")
451+
452+
if component.isMultiThreadedEnv() {
453+
lockInstanceMethod := LockInstanceMethod()
454+
w.Writeln(" /**")
455+
w.Writeln(" * %s::%s - %s", classInterfaceName, lockInstanceMethod.MethodName, lockInstanceMethod.MethodDescription)
456+
w.Writeln(" */")
457+
w.Writeln(" virtual void %s() {}", lockInstanceMethod.MethodName)
458+
w.Writeln("")
459+
460+
unlockInstanceMethod := UnlockInstanceMethod()
461+
w.Writeln(" /**")
462+
w.Writeln(" * %s::%s - %s", classInterfaceName, unlockInstanceMethod.MethodName, unlockInstanceMethod.MethodDescription)
463+
w.Writeln(" */")
464+
w.Writeln(" virtual void %s() {}", unlockInstanceMethod.MethodName)
465+
w.Writeln("")
466+
}
415467
}
416468

417469
if (component.isBaseClass(class)) {
@@ -440,6 +492,11 @@ func writeCPPClassInterface(component ComponentDefinition, class ComponentDefini
440492
if method.MethodName == component.Global.ClassTypeIdMethod {
441493
continue
442494
}
495+
496+
if component.isBaseClass(class) && method.isExtraBaseClassmethod() {
497+
continue
498+
}
499+
443500
methodstring, _, err := buildCPPInterfaceMethodDeclaration(method, class.ClassName, NameSpace, ClassIdentifier, BaseName, w.IndentString, false, true, true)
444501
if err != nil {
445502
return err
@@ -452,6 +509,9 @@ func writeCPPClassInterface(component ComponentDefinition, class ComponentDefini
452509

453510
if component.isBaseClass(class) {
454511
writeSharedPtrTemplate(component, w, ClassIdentifier)
512+
if component.isMultiThreadedEnv() {
513+
writeBaseInterfaceWithMutexClass(class, w, ClassIdentifier)
514+
}
455515
}
456516

457517
w.Writeln("")
@@ -535,6 +595,9 @@ func buildCPPInterfaces(component ComponentDefinition, w LanguageWriter, NameSpa
535595

536596
w.Writeln("#include <string>")
537597
w.Writeln("#include <memory>")
598+
if component.isMultiThreadedEnv() {
599+
w.Writeln("#include <mutex>")
600+
}
538601
w.Writeln("")
539602
w.Writeln("#include \"%s_types.hpp\"", BaseName)
540603
w.Writeln("")

0 commit comments

Comments
 (0)