storage/SQLCollations.cpp
author Nicholas Nethercote <nnethercote@mozilla.com>
Fri, 16 Feb 2018 17:54:16 +1100
changeset 407868 32d6774930e55be5c03e8d631fc067a995623c1e
parent 252629 91d6e262b662a0b4e47358665e222d3927337af9
child 448947 6f3709b3878117466168c40affa7bca0b60cf75b
permissions -rw-r--r--
Bug 1438678 - Pass early prefs via shared memory instead of the command line. r=bobowen,jld,glandium. This patch replaces the large -intPrefs/-boolPrefs/-stringPrefs flags with a short-lived, anonymous, shared memory segment that is used to pass the early prefs. Removing the bloat from the command line is nice, but more important is the fact that this will let us pass more prefs at content process start-up, which will allow us to remove the early/late prefs split (bug 1436911). Although this mechanism is only used for prefs, it's conceivable that it could be used for other data that must be received very early by children, and for which the command line isn't ideal. Notable details: - Much of the patch deals with the various platform-specific ways of passing handles/fds to children. - Linux and Mac: we use a fixed fd (8) in combination with the new GeckoChildProcessHost::AddFdToRemap() function (which ensures the child won't close the fd). - Android: like Linux and Mac, but the handles get passed via "parcels" and we use the new SetPrefsFd() function instead of the fixed fd. - Windows: there is no need to duplicate the handle because Windows handles are system-wide. But we do use the new GeckoChildProcessHost::AddHandleToShare() function to add it to the list of inheritable handles. We also ensure that list is processed on all paths (MOZ_SANDBOX with sandbox, MOZ_SANDBOX without sandbox, non-MOZ_SANDBOX) so that the handles are marked as inheritable. The handle is passed via the -prefsHandle flag. The -prefsLen flag is used on all platforms to indicate the size of the shared memory segment. - The patch also moves the serialization/deserialization of the prefs in/out of the shared memory into libpref, which is a better spot for it. (This means Preferences::MustSendToContentProcesses() can be removed.) MozReview-Commit-ID: 8fREEBiYFvc

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/ArrayUtils.h"

#include "SQLCollations.h"

namespace mozilla {
namespace storage {

////////////////////////////////////////////////////////////////////////////////
//// Local Helper Functions

namespace {

/**
 * Helper function for the UTF-8 locale collations.
 *
 * @param  aService
 *         The Service that owns the nsICollation used by this collation.
 * @param  aLen1
 *         The number of bytes in aStr1.
 * @param  aStr1
 *         The string to be compared against aStr2 as provided by SQLite.  It
 *         must be a non-null-terminated char* buffer.
 * @param  aLen2
 *         The number of bytes in aStr2.
 * @param  aStr2
 *         The string to be compared against aStr1 as provided by SQLite.  It
 *         must be a non-null-terminated char* buffer.
 * @param  aComparisonStrength
 *         The sorting strength, one of the nsICollation constants.
 * @return aStr1 - aStr2.  That is, if aStr1 < aStr2, returns a negative number.
 *         If aStr1 > aStr2, returns a positive number.  If aStr1 == aStr2,
 *         returns 0.
 */
int
localeCollationHelper8(void *aService,
                       int aLen1,
                       const void *aStr1,
                       int aLen2,
                       const void *aStr2,
                       int32_t aComparisonStrength)
{
  NS_ConvertUTF8toUTF16 str1(static_cast<const char *>(aStr1), aLen1);
  NS_ConvertUTF8toUTF16 str2(static_cast<const char *>(aStr2), aLen2);
  Service *serv = static_cast<Service *>(aService);
  return serv->localeCompareStrings(str1, str2, aComparisonStrength);
}

/**
 * Helper function for the UTF-16 locale collations.
 *
 * @param  aService
 *         The Service that owns the nsICollation used by this collation.
 * @param  aLen1
 *         The number of bytes (not characters) in aStr1.
 * @param  aStr1
 *         The string to be compared against aStr2 as provided by SQLite.  It
 *         must be a non-null-terminated char16_t* buffer.
 * @param  aLen2
 *         The number of bytes (not characters) in aStr2.
 * @param  aStr2
 *         The string to be compared against aStr1 as provided by SQLite.  It
 *         must be a non-null-terminated char16_t* buffer.
 * @param  aComparisonStrength
 *         The sorting strength, one of the nsICollation constants.
 * @return aStr1 - aStr2.  That is, if aStr1 < aStr2, returns a negative number.
 *         If aStr1 > aStr2, returns a positive number.  If aStr1 == aStr2,
 *         returns 0.
 */
int
localeCollationHelper16(void *aService,
                        int aLen1,
                        const void *aStr1,
                        int aLen2,
                        const void *aStr2,
                        int32_t aComparisonStrength)
{
  const char16_t *buf1 = static_cast<const char16_t *>(aStr1);
  const char16_t *buf2 = static_cast<const char16_t *>(aStr2);

  // The second argument to the nsDependentSubstring constructor is exclusive:
  // It points to the char16_t immediately following the last one in the target
  // substring.  Since aLen1 and aLen2 are in bytes, divide by sizeof(char16_t)
  // so that the pointer arithmetic is correct.
  nsDependentSubstring str1(buf1, buf1 + (aLen1 / sizeof(char16_t)));
  nsDependentSubstring str2(buf2, buf2 + (aLen2 / sizeof(char16_t)));
  Service *serv = static_cast<Service *>(aService);
  return serv->localeCompareStrings(str1, str2, aComparisonStrength);
}

// This struct is used only by registerCollations below, but ISO C++98 forbids
// instantiating a template dependent on a locally-defined type.  Boo-urns!
struct Collations {
  const char *zName;
  int enc;
  int(*xCompare)(void*, int, const void*, int, const void*);
};

} // namespace

////////////////////////////////////////////////////////////////////////////////
//// Exposed Functions

int
registerCollations(sqlite3 *aDB,
                   Service *aService)
{
  Collations collations[] = {
    {"locale",
     SQLITE_UTF8,
     localeCollation8},
    {"locale_case_sensitive",
     SQLITE_UTF8,
     localeCollationCaseSensitive8},
    {"locale_accent_sensitive",
     SQLITE_UTF8,
     localeCollationAccentSensitive8},
    {"locale_case_accent_sensitive",
     SQLITE_UTF8,
     localeCollationCaseAccentSensitive8},
    {"locale",
     SQLITE_UTF16,
     localeCollation16},
    {"locale_case_sensitive",
     SQLITE_UTF16,
     localeCollationCaseSensitive16},
    {"locale_accent_sensitive",
     SQLITE_UTF16,
     localeCollationAccentSensitive16},
    {"locale_case_accent_sensitive",
     SQLITE_UTF16,
     localeCollationCaseAccentSensitive16},
  };

  int rv = SQLITE_OK;
  for (size_t i = 0; SQLITE_OK == rv && i < ArrayLength(collations); ++i) {
    struct Collations *p = &collations[i];
    rv = ::sqlite3_create_collation(aDB, p->zName, p->enc, aService,
                                    p->xCompare);
  }

  return rv;
}

////////////////////////////////////////////////////////////////////////////////
//// SQL Collations

int
localeCollation8(void *aService,
                 int aLen1,
                 const void *aStr1,
                 int aLen2,
                 const void *aStr2)
{
  return localeCollationHelper8(aService, aLen1, aStr1, aLen2, aStr2,
                                nsICollation::kCollationCaseInSensitive);
}

int
localeCollationCaseSensitive8(void *aService,
                              int aLen1,
                              const void *aStr1,
                              int aLen2,
                              const void *aStr2)
{
  return localeCollationHelper8(aService, aLen1, aStr1, aLen2, aStr2,
                                nsICollation::kCollationAccentInsenstive);
}

int
localeCollationAccentSensitive8(void *aService,
                                int aLen1,
                                const void *aStr1,
                                int aLen2,
                                const void *aStr2)
{
  return localeCollationHelper8(aService, aLen1, aStr1, aLen2, aStr2,
                                nsICollation::kCollationCaseInsensitiveAscii);
}

int
localeCollationCaseAccentSensitive8(void *aService,
                                    int aLen1,
                                    const void *aStr1,
                                    int aLen2,
                                    const void *aStr2)
{
  return localeCollationHelper8(aService, aLen1, aStr1, aLen2, aStr2,
                                nsICollation::kCollationCaseSensitive);
}

int
localeCollation16(void *aService,
                  int aLen1,
                  const void *aStr1,
                  int aLen2,
                  const void *aStr2)
{
  return localeCollationHelper16(aService, aLen1, aStr1, aLen2, aStr2,
                                 nsICollation::kCollationCaseInSensitive);
}

int
localeCollationCaseSensitive16(void *aService,
                               int aLen1,
                               const void *aStr1,
                               int aLen2,
                               const void *aStr2)
{
  return localeCollationHelper16(aService, aLen1, aStr1, aLen2, aStr2,
                                 nsICollation::kCollationAccentInsenstive);
}

int
localeCollationAccentSensitive16(void *aService,
                                 int aLen1,
                                 const void *aStr1,
                                 int aLen2,
                                 const void *aStr2)
{
  return localeCollationHelper16(aService, aLen1, aStr1, aLen2, aStr2,
                                 nsICollation::kCollationCaseInsensitiveAscii);
}

int
localeCollationCaseAccentSensitive16(void *aService,
                                     int aLen1,
                                     const void *aStr1,
                                     int aLen2,
                                     const void *aStr2)
{
  return localeCollationHelper16(aService, aLen1, aStr1, aLen2, aStr2,
                                 nsICollation::kCollationCaseSensitive);
}

} // namespace storage
} // namespace mozilla