// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "vm/version.h"

#include "vm/cpu.h"
#include "vm/os.h"

namespace dart {

// TODO(iposva): Avoid racy initialization.
static const char* formatted_version = NULL;

const char* Version::String() {
  if (formatted_version == NULL) {
    const char* os = OS::Name();
    const char* arch = CPU::Id();
    formatted_version = OS::SCreate(NULL, "%s on \"%s_%s\"", str_, os, arch);
  }
  return formatted_version;
}

const char* Version::SnapshotString() {
  return snapshot_hash_;
}

const char* Version::CommitString() {
  return commit_;
}

const char* Version::SdkHash() {
  return git_short_hash_;
}

const char* Version::snapshot_hash_ = "{{SNAPSHOT_HASH}}";
const char* Version::str_ = "{{VERSION_STR}} ({{CHANNEL}}) ({{COMMIT_TIME}})";
const char* Version::commit_ = "{{VERSION_STR}}";
const char* Version::git_short_hash_ = "{{GIT_HASH}}";

}  // namespace dart

// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "platform/atomic.h"

#include "vm/cpu.h"
#include "vm/os.h"
#include "vm/version.h"

namespace dart {

// We use require-release semantics to ensure initializing stores to the string
// are visible when the string becomes visible.
static AcqRelAtomic<const char*> formatted_version = nullptr;

const char* Version::String() {
  if (formatted_version.load() == nullptr) {
    const char* os = OS::Name();
    const char* arch = CPU::Id();
    char* version_string =
        OS::SCreate(nullptr, "%s on \"%s_%s\"", str_, os, arch);
    const char* expect_old_is_null = nullptr;
    if (!formatted_version.compare_exchange_strong(expect_old_is_null,
                                                   version_string)) {
      free(version_string);
    }
  }
  return formatted_version.load();
}

const char* Version::SnapshotString() {
  return snapshot_hash_;
}

const char* Version::CommitString() {
  return commit_;
}

const char* Version::SdkHash() {
  return git_short_hash_;
}

const char* Version::snapshot_hash_ = "{{SNAPSHOT_HASH}}";
const char* Version::str_ = "{{VERSION_STR}} ({{CHANNEL}}) ({{COMMIT_TIME}})";
const char* Version::commit_ = "{{VERSION_STR}}";
const char* Version::git_short_hash_ = "{{GIT_HASH}}";

}  // namespace dart

Use atomic to avoid racy version string initialization
[vm] Use atomic to avoid racy version string initialization

This addresses an already existent TODO in the code.

Issue https://github.com/dart-lang/sdk/issues/46610

TEST=This fixes TSAN reports on iso-stress builder.

Change-Id: Ie21c0a17ae51070783da9bc934ef2827acde6378
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/206760
Reviewed-by: Tess Strickland <cce218d042444252b7ac446d60910fca7732559c@google.com>
Commit-Queue: Martin Kustermann <a35dd5b79fac84b2bb3b026a16b8becc55af5961@google.com>
