Skip to content

Commit ead0af7

Browse files
committed
Fix 2 problems in client_tcert_pool_mt.go, including one causing deadlock.
Fixed 2 obvious problems in client_tcert_pool_mt.go. - Function (*tCertPoolEntry).GetNextTCert() should be thread-safe, so that it doesn't make sense to put tCertBlock to shared object field. - Function (*tCertPoolMultithreadingImpl).Start() shouldn't call poolEntry.Start(), as it was already called inside tCertPool.getPoolEntry(attributes). The latter problem was causing deadlock (due to insufficient channel size). To reproduce, run go test -run=TestClientGetNextTCerts at crypto directory, using a version of crypto_test.go in this commit (reverting #1809). This commit also includes a fix of TestClientGetAttributesFromTCertWithUnusedTCerts, (using fresh client, not reusing the old one). Change-Id: I1b4bd0dd111ebaf182a87dc5f3ecd3e4c0278a0f Signed-off-by: Akihiko Tozawa <[email protected]>
1 parent fb7da0d commit ead0af7

File tree

2 files changed

+21
-15
lines changed

2 files changed

+21
-15
lines changed

core/crypto/client_tcert_pool_mt.go

+8-13
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,14 @@ type tCertPoolEntry struct {
3030
tCertChannelFeedback chan struct{}
3131
done chan struct{}
3232
client *clientImpl
33-
tCertBlock *TCertBlock
3433
}
3534

3635
//NewTCertPoolEntry creates a new tcert pool entry
3736
func newTCertPoolEntry(client *clientImpl, attributes []string) *tCertPoolEntry {
3837
tCertChannel := make(chan *TCertBlock, client.conf.getTCertBatchSize()*2)
3938
tCertChannelFeedback := make(chan struct{}, client.conf.getTCertBatchSize()*2)
4039
done := make(chan struct{}, 1)
41-
return &tCertPoolEntry{attributes, tCertChannel, tCertChannelFeedback, done, client, nil}
40+
return &tCertPoolEntry{attributes, tCertChannel, tCertChannelFeedback, done, client}
4241
}
4342

4443
//Start starts the pool entry filler loop.
@@ -85,25 +84,24 @@ func (tCertPoolEntry *tCertPoolEntry) GetNextTCert(attributes ...string) (tCertB
8584
for i := 0; i < 3; i++ {
8685
tCertPoolEntry.client.Debugf("Getting next TCert... %d out of 3", i)
8786
select {
88-
case tCertPoolEntry.tCertBlock = <-tCertPoolEntry.tCertChannel:
87+
case tCertBlock = <-tCertPoolEntry.tCertChannel:
8988
break
9089
case <-time.After(30 * time.Second):
9190
tCertPoolEntry.client.Error("Failed getting a new TCert. Buffer is empty!")
9291
}
93-
if tCertPoolEntry.tCertBlock != nil {
92+
if tCertBlock != nil {
9493
// Send feedback to the filler
9594
tCertPoolEntry.client.Debug("Send feedback")
9695
tCertPoolEntry.tCertChannelFeedback <- struct{}{}
9796
break
9897
}
9998
}
10099

101-
if tCertPoolEntry.tCertBlock == nil {
100+
if tCertBlock == nil {
102101
// TODO: change error here
103102
return nil, errors.New("Failed getting a new TCert. Buffer is empty!")
104103
}
105104

106-
tCertBlock = tCertPoolEntry.tCertBlock
107105
tCertPoolEntry.client.Debugf("Cert [% x].", tCertBlock.tCert.GetCertificate().Raw)
108106

109107
// Store the TCert permanently
@@ -233,11 +231,8 @@ type tCertPoolMultithreadingImpl struct {
233231
func (tCertPool *tCertPoolMultithreadingImpl) Start() (err error) {
234232
// Start the filler, initializes a poolEntry without attributes.
235233
var attributes []string
236-
poolEntry, err := tCertPool.getPoolEntry(attributes)
237-
if err != nil {
238-
return err
239-
}
240-
return poolEntry.Start()
234+
_, err = tCertPool.getOrCreatePoolEntry(attributes)
235+
return
241236
}
242237

243238
func (tCertPool *tCertPoolMultithreadingImpl) lockEntries() {
@@ -273,7 +268,7 @@ func (tCertPool *tCertPoolMultithreadingImpl) getPoolEntryFromHash(attributeHash
273268
}
274269

275270
//Returns a tCertPoolEntry for the attributes "attributes", if the tCertPoolEntry doesn't exists a new tCertPoolEntry will be create for that attributes.
276-
func (tCertPool *tCertPoolMultithreadingImpl) getPoolEntry(attributes []string) (*tCertPoolEntry, error) {
271+
func (tCertPool *tCertPoolMultithreadingImpl) getOrCreatePoolEntry(attributes []string) (*tCertPoolEntry, error) {
277272
tCertPool.client.Debug("Getting pool entry %v \n", attributes)
278273
attributeHash := calculateAttributesHash(attributes)
279274
tCertPool.lockEntries()
@@ -307,7 +302,7 @@ func (tCertPool *tCertPoolMultithreadingImpl) GetNextTCerts(nCerts int, attribut
307302
}
308303

309304
func (tCertPool *tCertPoolMultithreadingImpl) getNextTCert(attributes ...string) (tCertBlock *TCertBlock, err error) {
310-
poolEntry, err := tCertPool.getPoolEntry(attributes)
305+
poolEntry, err := tCertPool.getOrCreatePoolEntry(attributes)
311306
if err != nil {
312307
return nil, err
313308
}

core/crypto/crypto_test.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ func TestMain(m *testing.M) {
8383
os.Exit(ret)
8484
}
8585

86+
//Second scenario with multithread
87+
properties["security.multithreading.enabled"] = "true"
88+
ret = runTestsOnScenario(m, properties, "Using multithread enabled")
89+
if ret != 0 {
90+
os.Exit(ret)
91+
}
92+
properties["security.multithreading.enabled"] = "false"
93+
8694
//Fourth scenario with security level = 384
8795
properties["security.hashAlgorithm"] = "SHA3"
8896
properties["security.level"] = "384"
@@ -432,6 +440,9 @@ func TestClientMultiExecuteTransaction(t *testing.T) {
432440

433441
func TestClientGetNextTCerts(t *testing.T) {
434442

443+
initNodes()
444+
defer closeNodes()
445+
435446
// Some positive flow tests here
436447
var nCerts int = 1
437448
for i := 1; i < 3; i++ {
@@ -509,8 +520,8 @@ func TestClientGetAttributesFromTCertWithUnusedTCerts(t *testing.T) {
509520

510521
_, _ = deployer.GetNextTCerts(1, attrs...)
511522

512-
after() //Tear down the server.
513-
before() //Start up again to use unsed TCerts
523+
CloseAllClients() // Remove client and store unused TCerts.
524+
initClients() // Restart fresh client.
514525

515526
tcerts, err := deployer.GetNextTCerts(1, attrs...)
516527

0 commit comments

Comments
 (0)