<commit_before>/*
 * Copyright 2010-2017 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef KONAN_ANDROID
#include <android/log.h>
#endif
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#if !KONAN_NO_THREADS
#include <pthread.h>
#endif
#include <unistd.h>
#if KONAN_WINDOWS
#include <windows.h>
#endif

#include <chrono>

#include "Common.h"
#include "Porting.h"

#if KONAN_WASM || KONAN_ZEPHYR
extern "C" RUNTIME_NORETURN void Konan_abort(const char*);
extern "C" RUNTIME_NORETURN void Konan_exit(int32_t status);
#endif
#ifdef KONAN_ZEPHYR
// In Zephyr's Newlib strnlen(3) is not included from string.h by default.
extern "C" size_t strnlen(const char* buffer, size_t maxSize);
#endif

namespace konan {

// Console operations.
void consoleInit() {
#if KONAN_WINDOWS
  // Note that this code enforces UTF-8 console output, so we may want to rethink
  // how we perform console IO, if it turns out, that UTF-16 is better output format.
  ::SetConsoleCP(CP_UTF8);
  ::SetConsoleOutputCP(CP_UTF8);
#endif
}

void consoleWriteUtf8(const void* utf8, uint32_t sizeBytes) {
#ifdef KONAN_ANDROID
  // TODO: use sizeBytes!
  __android_log_print(ANDROID_LOG_INFO, "Konan_main", "%s", utf8);
#else
  ::write(STDOUT_FILENO, utf8, sizeBytes);
#endif
}

void consoleErrorUtf8(const void* utf8, uint32_t sizeBytes) {
#ifdef KONAN_ANDROID
  // TODO: use sizeBytes!
  __android_log_print(ANDROID_LOG_ERROR, "Konan_main", "%s", utf8);
#else
  ::write(STDERR_FILENO, utf8, sizeBytes);
#endif
}

int32_t consoleReadUtf8(void* utf8, uint32_t maxSizeBytes) {
#ifdef KONAN_ZEPHYR
  return 0;
#else
  auto length = ::read(STDIN_FILENO, utf8, maxSizeBytes - 1);
  if (length <= 0) return -1;
  char* start = reinterpret_cast<char*>(utf8);
  char* current = start + length - 1;
  bool isTrimming = true;
  while (current >= start && isTrimming) {
    switch (*current) {
      case '\n':
      case '\r':
        *current = 0;
        length--;
        break;
      default:
        isTrimming = false;
    }
    current--;
  }
  return length;
#endif
}

#if KONAN_INTERNAL_SNPRINTF
extern "C" int rpl_vsnprintf(char *, size_t, const char *, va_list);
#define vsnprintf_impl rpl_vsnprintf
#else
#define vsnprintf_impl ::vsnprintf
#endif

void consolePrintf(const char* format, ...) {
  char buffer[1024];
  va_list args;
  va_start(args, format);
  int rv = vsnprintf_impl(buffer, sizeof(buffer) - 1, format, args);
  va_end(args);
  consoleWriteUtf8(buffer, rv);
}

// Thread execution.
#if !KONAN_NO_THREADS

pthread_key_t terminationKey;
pthread_once_t terminationKeyOnceControl =  PTHREAD_ONCE_INIT;

typedef void (*destructor_t)(void*);

struct DestructorRecord {
  struct DestructorRecord* next;
  destructor_t destructor;
  void* destructorParameter;
};

static void onThreadExitCallback(void* value) {
  DestructorRecord* record = reinterpret_cast<DestructorRecord*>(value);
  while (record != nullptr) {
    record->destructor(record->destructorParameter);
    auto next = record->next;
    free(record);
    record = next;
  }
  pthread_setspecific(terminationKey, nullptr);
}

static void onThreadExitInit() {
  pthread_key_create(&terminationKey, onThreadExitCallback);
}

#endif  // !KONAN_NO_THREADS

void onThreadExit(void (*destructor)(void*), void* destructorParameter) {
#if KONAN_NO_THREADS<commit_msg>Avoid Valgrind message due to glibc bug. (#3768)<commit_after>/*
 * Copyright 2010-2017 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef KONAN_ANDROID
#include <android/log.h>
#endif
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#if !KONAN_NO_THREADS
#include <pthread.h>
#endif
#include <unistd.h>
#if KONAN_WINDOWS
#include <windows.h>
#endif

#include <chrono>

#include "Common.h"
#include "Porting.h"

#if KONAN_WASM || KONAN_ZEPHYR
extern "C" RUNTIME_NORETURN void Konan_abort(const char*);
extern "C" RUNTIME_NORETURN void Konan_exit(int32_t status);
#endif
#ifdef KONAN_ZEPHYR
// In Zephyr's Newlib strnlen(3) is not included from string.h by default.
extern "C" size_t strnlen(const char* buffer, size_t maxSize);
#endif

namespace konan {

// Console operations.
void consoleInit() {
#if KONAN_WINDOWS
  // Note that this code enforces UTF-8 console output, so we may want to rethink
  // how we perform console IO, if it turns out, that UTF-16 is better output format.
  ::SetConsoleCP(CP_UTF8);
  ::SetConsoleOutputCP(CP_UTF8);
#endif
}

void consoleWriteUtf8(const void* utf8, uint32_t sizeBytes) {
#ifdef KONAN_ANDROID
  // TODO: use sizeBytes!
  __android_log_print(ANDROID_LOG_INFO, "Konan_main", "%s", utf8);
#else
  ::write(STDOUT_FILENO, utf8, sizeBytes);
#endif
}

void consoleErrorUtf8(const void* utf8, uint32_t sizeBytes) {
#ifdef KONAN_ANDROID
  // TODO: use sizeBytes!
  __android_log_print(ANDROID_LOG_ERROR, "Konan_main", "%s", utf8);
#else
  ::write(STDERR_FILENO, utf8, sizeBytes);
#endif
}

int32_t consoleReadUtf8(void* utf8, uint32_t maxSizeBytes) {
#ifdef KONAN_ZEPHYR
  return 0;
#else
  auto length = ::read(STDIN_FILENO, utf8, maxSizeBytes - 1);
  if (length <= 0) return -1;
  char* start = reinterpret_cast<char*>(utf8);
  char* current = start + length - 1;
  bool isTrimming = true;
  while (current >= start && isTrimming) {
    switch (*current) {
      case '\n':
      case '\r':
        *current = 0;
        length--;
        break;
      default:
        isTrimming = false;
    }
    current--;
  }
  return length;
#endif
}

#if KONAN_INTERNAL_SNPRINTF
extern "C" int rpl_vsnprintf(char *, size_t, const char *, va_list);
#define vsnprintf_impl rpl_vsnprintf
#else
#define vsnprintf_impl ::vsnprintf
#endif

void consolePrintf(const char* format, ...) {
  char buffer[1024];
  va_list args;
  va_start(args, format);
  int rv = vsnprintf_impl(buffer, sizeof(buffer) - 1, format, args);
  va_end(args);
  consoleWriteUtf8(buffer, rv);
}

// Thread execution.
#if !KONAN_NO_THREADS

pthread_key_t terminationKey;
pthread_once_t terminationKeyOnceControl = PTHREAD_ONCE_INIT;

typedef void (*destructor_t)(void*);

struct DestructorRecord {
  struct DestructorRecord* next;
  destructor_t destructor;
  void* destructorParameter;
};

static void onThreadExitCallback(void* value) {
  DestructorRecord* record = reinterpret_cast<DestructorRecord*>(value);
  while (record != nullptr) {
    record->destructor(record->destructorParameter);
    auto next = record->next;
    free(record);
    record = next;
  }
  pthread_setspecific(terminationKey, nullptr);
}

#if KONAN_LINUX
static pthread_key_t dummyKey;
#endif
static void onThreadExitInit() {
#if KONAN_LINUX
  // Due to glibc bug we have to create first key as dummy, to avoid
  // conflicts with potentially uninitialized dlfcn error key.
  // https://code.woboq.org/userspace/glibc/dlfcn/dlerror.c.html#237
  // As one may see, glibc checks value of the key even if it was not inited (and == 0),
  // and so data associated with our legit key (== 0 as being the first one) is used.
  // Other libc are not affected, as usually == 0 pthread key is impossible.
  pthread_key_create(&dummyKey, nullptr);
#endif
  pthread_key_create(&terminationKey, onThreadExitCallback);
}

#endif  // !KONAN_NO_THREADS

void onThreadExit(void (*destructor)(void*), void* destructorParameter) {
#if KONAN_NO_THREADS
{'fraction_non_alphanumeric': 0.11152283050442266, 'fraction_numerical': 0.013626583791537174, 'mean_word_length': 4.486557377049181, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 35, 'https://': 1, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5809730', 'n_tokens_mistral': 3005, 'n_tokens_neox': 2896, 'n_words': 843}