зеркало из https://github.com/mozilla/pjs.git
Bug 599545 - Investigate remote-prefs serialization performance. r=dwitte, a=blocking-fennec2.0b2+
This commit is contained in:
Родитель
80f231dc57
Коммит
3a55459851
|
@ -383,10 +383,14 @@ ContentChild::AddRemoteAlertObserver(const nsString& aData,
|
|||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvPreferenceUpdate(const nsCString& aPref)
|
||||
ContentChild::RecvPreferenceUpdate(const PrefTuple& aPref)
|
||||
{
|
||||
nsCOMPtr<nsIPrefServiceInternal> prefs = do_GetService("@mozilla.org/preferences-service;1");
|
||||
prefs->ReadPrefBuffer(aPref);
|
||||
if (!prefs)
|
||||
return false;
|
||||
|
||||
prefs->SetPreference(&aPref);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -104,8 +104,8 @@ public:
|
|||
// auto remove when alertfinished is received.
|
||||
nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver);
|
||||
|
||||
virtual bool RecvPreferenceUpdate(const nsCString& aDomain);
|
||||
|
||||
virtual bool RecvPreferenceUpdate(const PrefTuple& aPref);
|
||||
|
||||
virtual bool RecvNotifyAlertsObserver(const nsCString& aType, const nsString& aData);
|
||||
|
||||
virtual bool RecvAsyncMessage(const nsString& aMsg, const nsString& aJSON);
|
||||
|
|
|
@ -196,10 +196,10 @@ ContentParent::IsAlive()
|
|||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvReadPrefs(nsCString* prefs)
|
||||
ContentParent::RecvReadPrefsArray(nsTArray<PrefTuple> *prefs)
|
||||
{
|
||||
EnsurePrefService();
|
||||
mPrefService->SerializePreferences(*prefs);
|
||||
mPrefService->MirrorPreferences(prefs);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -301,10 +301,14 @@ ContentParent::Observe(nsISupports* aSubject,
|
|||
if (!strcmp(aTopic, "nsPref:changed")) {
|
||||
// We know prefs are ASCII here.
|
||||
NS_LossyConvertUTF16toASCII strData(aData);
|
||||
nsCString prefBuffer;
|
||||
nsCOMPtr<nsIPrefServiceInternal> prefs = do_GetService("@mozilla.org/preferences-service;1");
|
||||
prefs->SerializePreference(strData, prefBuffer);
|
||||
if (!SendPreferenceUpdate(prefBuffer))
|
||||
|
||||
PrefTuple pref;
|
||||
nsCOMPtr<nsIPrefServiceInternal> prefService =
|
||||
do_GetService("@mozilla.org/preferences-service;1");
|
||||
|
||||
prefService->MirrorPreference(strData, &pref);
|
||||
|
||||
if (!SendPreferenceUpdate(pref))
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC)) {
|
||||
|
|
|
@ -125,7 +125,7 @@ private:
|
|||
const PRInt64& aContentLength);
|
||||
virtual bool DeallocPExternalHelperApp(PExternalHelperAppParent* aService);
|
||||
|
||||
virtual bool RecvReadPrefs(nsCString* prefs);
|
||||
virtual bool RecvReadPrefsArray(nsTArray<PrefTuple> *retValue);
|
||||
|
||||
void EnsurePrefService();
|
||||
|
||||
|
|
|
@ -45,8 +45,11 @@ include "mozilla/chrome/RegistryMessageUtils.h";
|
|||
include "mozilla/net/NeckoMessageUtils.h";
|
||||
|
||||
include "nsGeoPositionIPCSerialiser.h";
|
||||
include "PPrefTuple.h";
|
||||
|
||||
using GeoPosition;
|
||||
using PrefTuple;
|
||||
using nsTArray<PrefTuple>;
|
||||
|
||||
using ChromePackage;
|
||||
using ResourceMapping;
|
||||
|
@ -76,7 +79,7 @@ child:
|
|||
|
||||
async NotifyVisited(URI uri);
|
||||
|
||||
PreferenceUpdate(nsCString pref);
|
||||
PreferenceUpdate(PrefTuple pref);
|
||||
|
||||
NotifyAlertsObserver(nsCString topic, nsString data);
|
||||
|
||||
|
@ -96,8 +99,8 @@ parent:
|
|||
|
||||
async LoadURIExternal(URI uri);
|
||||
|
||||
// PrefService messages
|
||||
sync ReadPrefs() returns (nsCString retValue);
|
||||
// PrefService message
|
||||
sync ReadPrefsArray() returns (nsTArray<PrefTuple> retValue);
|
||||
|
||||
sync SyncMessage(nsString aMessage, nsString aJSON)
|
||||
returns (nsString[] retval);
|
||||
|
|
|
@ -57,5 +57,10 @@ XPIDLSRCS = \
|
|||
nsIRelativeFilePref.idl \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = \
|
||||
PPrefTuple.h \
|
||||
PrefTuple.h
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla preference service code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Mike Kristoffersen <moz@mikek.dk> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef dom_pref_hash_entry_array_IPC_serialiser
|
||||
#define dom_pref_hash_entry_array_IPC_serialiser
|
||||
|
||||
#include "IPC/IPCMessageUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "pldhash.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "PrefTuple.h"
|
||||
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template <>
|
||||
struct ParamTraits<PrefTuple>
|
||||
{
|
||||
typedef PrefTuple paramType;
|
||||
|
||||
// Function to serialize a PrefTuple
|
||||
static void Write(Message *aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.key);
|
||||
WriteParam(aMsg, (PRUint32)aParam.type);
|
||||
switch (aParam.type) {
|
||||
case PrefTuple::PREF_STRING:
|
||||
WriteParam(aMsg, aParam.stringVal);
|
||||
break;
|
||||
case PrefTuple::PREF_INT:
|
||||
WriteParam(aMsg, aParam.intVal);
|
||||
break;
|
||||
case PrefTuple::PREF_BOOL:
|
||||
WriteParam(aMsg, aParam.boolVal);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to de-serialize a PrefTuple
|
||||
static bool Read(const Message* aMsg, void **aIter, paramType* aResult)
|
||||
{
|
||||
PRUint32 type;
|
||||
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->key)))
|
||||
return false;
|
||||
|
||||
if (!ReadParam(aMsg, aIter, &type))
|
||||
return false;
|
||||
|
||||
switch (type) {
|
||||
case PrefTuple::PREF_STRING:
|
||||
aResult->type = PrefTuple::PREF_STRING;
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->stringVal)))
|
||||
return false;
|
||||
break;
|
||||
case PrefTuple::PREF_INT:
|
||||
aResult->type = PrefTuple::PREF_INT;
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->intVal)))
|
||||
return false;
|
||||
break;
|
||||
case PrefTuple::PREF_BOOL:
|
||||
aResult->type = PrefTuple::PREF_BOOL;
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->boolVal)))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} ;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla preference service code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Mike Kristoffersen <moz@mikek.dk> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef preftuple_included
|
||||
#define preftuple_included
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "nsString.h"
|
||||
|
||||
struct PrefTuple
|
||||
{
|
||||
nsCAutoString key;
|
||||
|
||||
// We don't use a union to avoid allocations when using the string component
|
||||
// NOTE: Only one field will be valid at any given time, as indicated by the type enum
|
||||
nsCAutoString stringVal;
|
||||
PRInt32 intVal;
|
||||
bool boolVal;
|
||||
|
||||
enum {
|
||||
PREF_STRING,
|
||||
PREF_INT,
|
||||
PREF_BOOL
|
||||
} type;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -40,6 +40,15 @@
|
|||
#include "nsISupports.idl"
|
||||
#include "nsIPrefBranch.idl"
|
||||
|
||||
%{C++
|
||||
struct PrefTuple;
|
||||
template<class E> class nsTArray;
|
||||
%}
|
||||
|
||||
[ptr] native nsPreferencesArrayPtr(nsTArray<PrefTuple>);
|
||||
[ptr] native nsPreferencePtr(PrefTuple);
|
||||
[ptr] native nsPreferencePtrConst(const PrefTuple);
|
||||
|
||||
interface nsIFile;
|
||||
interface nsILocalFile;
|
||||
|
||||
|
@ -169,19 +178,19 @@ interface nsIPrefServiceInternal : nsISupports
|
|||
*/
|
||||
void readExtensionPrefs(in nsILocalFile aFile);
|
||||
|
||||
ACString serializePreferences();
|
||||
ACString serializePreference(in ACString aPrefName);
|
||||
void readPrefBuffer(in ACString aBuffer);
|
||||
[noscript] void mirrorPreferences(in nsPreferencesArrayPtr aArray);
|
||||
[noscript] void mirrorPreference(in ACString aPrefName, in nsPreferencePtr aPref);
|
||||
[noscript] void setPreference(in nsPreferencePtrConst aPref);
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
||||
#define NS_PREFSERVICE_CID \
|
||||
{ /* {1cd91b88-1dd2-11b2-92e1-ed22ed298000} */ \
|
||||
0x1cd91b88, \
|
||||
0x1dd2, \
|
||||
0x11b2, \
|
||||
{ 0x92, 0xe1, 0xed, 0x22, 0xed, 0x29, 0x80, 0x00 } \
|
||||
0x91ca2441, \
|
||||
0x050f, \
|
||||
0x4f7c, \
|
||||
{ 0x9d, 0xf8, 0x75, 0xb4, 0x0e, 0xa4, 0x01, 0x56 } \
|
||||
}
|
||||
|
||||
#define NS_PREFSERVICE_CONTRACTID "@mozilla.org/preferences-service;1"
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
#include "prefapi.h"
|
||||
#include "prefread.h"
|
||||
#include "prefapi_private_data.h"
|
||||
#include "PrefTuple.h"
|
||||
|
||||
#include "nsITimelineService.h"
|
||||
|
||||
|
@ -143,12 +144,15 @@ nsresult nsPrefService::Init()
|
|||
#ifdef MOZ_IPC
|
||||
using mozilla::dom::ContentChild;
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
nsTArray<PrefTuple> array;
|
||||
ContentChild::GetSingleton()->SendReadPrefsArray(&array);
|
||||
|
||||
ContentChild* cpc = ContentChild::GetSingleton();
|
||||
nsCAutoString prefs;
|
||||
cpc->SendReadPrefs(&prefs);
|
||||
|
||||
return ReadPrefBuffer(prefs);
|
||||
// Store the array
|
||||
nsTArray<PrefTuple>::size_type index = array.Length();
|
||||
while (index-- > 0) {
|
||||
pref_SetPrefTuple(array[index], PR_TRUE);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -328,58 +332,31 @@ NS_IMETHODIMP nsPrefService::ReadExtensionPrefs(nsILocalFile *aFile)
|
|||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPrefService::SerializePreferences(nsACString& prefs)
|
||||
NS_IMETHODIMP nsPrefService::SetPreference(const PrefTuple *aPref)
|
||||
{
|
||||
char** valueArray = (char **)PR_Calloc(sizeof(char *), gHashTable.entryCount);
|
||||
if (!valueArray)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
pref_saveArgs saveArgs;
|
||||
saveArgs.prefArray = valueArray;
|
||||
saveArgs.saveTypes = SAVE_ALL_AND_DEFAULTS;
|
||||
|
||||
// get the lines that we're supposed to be writing
|
||||
PL_DHashTableEnumerate(&gHashTable, pref_savePref, &saveArgs);
|
||||
|
||||
char** walker = valueArray;
|
||||
for (PRUint32 valueIdx = 0; valueIdx < gHashTable.entryCount; valueIdx++, walker++) {
|
||||
if (*walker) {
|
||||
prefs.Append(*walker);
|
||||
prefs.Append(NS_LINEBREAK);
|
||||
NS_Free(*walker);
|
||||
}
|
||||
}
|
||||
PR_Free(valueArray);
|
||||
|
||||
return NS_OK;
|
||||
return pref_SetPrefTuple(*aPref, PR_TRUE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPrefService::SerializePreference(const nsACString& aPrefName, nsACString& aBuffer)
|
||||
NS_IMETHODIMP nsPrefService::MirrorPreference(const nsACString& aPrefName,
|
||||
PrefTuple *aPref)
|
||||
{
|
||||
PrefHashEntry *pref = pref_HashTableLookup(nsDependentCString(aPrefName).get());
|
||||
|
||||
if (!pref)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
char* prefArray = nsnull;
|
||||
|
||||
pref_saveArgs saveArgs;
|
||||
saveArgs.prefArray = &prefArray;
|
||||
saveArgs.saveTypes = SAVE_ALL_AND_DEFAULTS;
|
||||
|
||||
pref_savePref(&gHashTable, pref, 0, &saveArgs);
|
||||
aBuffer = prefArray;
|
||||
PR_Free(prefArray);
|
||||
pref_GetTupleFromEntry(pref, aPref);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPrefService::ReadPrefBuffer(const nsACString& aBuffer)
|
||||
NS_IMETHODIMP nsPrefService::MirrorPreferences(nsTArray<PrefTuple> *aArray)
|
||||
{
|
||||
PrefParseState ps;
|
||||
PREF_InitParseState(&ps, PREF_ReaderCallback, NULL);
|
||||
nsresult rv = PREF_ParseBuf(&ps, nsDependentCString(aBuffer).get(), aBuffer.Length());
|
||||
PREF_FinalizeParseState(&ps);
|
||||
return rv;
|
||||
aArray->SetCapacity(PL_DHASH_TABLE_SIZE(&gHashTable));
|
||||
|
||||
PL_DHashTableEnumerate(&gHashTable, pref_MirrorPrefs, aArray);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPrefService::GetBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
#include "prefapi.h"
|
||||
#include "prefapi_private_data.h"
|
||||
#include "PrefTuple.h"
|
||||
#include "prefread.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsCRT.h"
|
||||
|
@ -310,6 +311,24 @@ PREF_SetBoolPref(const char *pref_name, PRBool value, PRBool set_default)
|
|||
return pref_HashPref(pref_name, pref, PREF_BOOL, set_default);
|
||||
}
|
||||
|
||||
nsresult
|
||||
pref_SetPrefTuple(const PrefTuple &aPref, PRBool set_default)
|
||||
{
|
||||
switch (aPref.type) {
|
||||
case PrefTuple::PREF_STRING:
|
||||
return PREF_SetCharPref(aPref.key.get(), aPref.stringVal.get(), set_default);
|
||||
|
||||
case PrefTuple::PREF_INT:
|
||||
return PREF_SetIntPref(aPref.key.get(), aPref.intVal, set_default);
|
||||
|
||||
case PrefTuple::PREF_BOOL:
|
||||
return PREF_SetBoolPref(aPref.key.get(), aPref.boolVal, set_default);
|
||||
}
|
||||
|
||||
NS_NOTREACHED("Unknown type");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
pref_savePref(PLDHashTable *table, PLDHashEntryHdr *heh, PRUint32 i, void *arg)
|
||||
{
|
||||
|
@ -367,6 +386,49 @@ pref_savePref(PLDHashTable *table, PLDHashEntryHdr *heh, PRUint32 i, void *arg)
|
|||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
pref_MirrorPrefs(PLDHashTable *table,
|
||||
PLDHashEntryHdr *heh,
|
||||
PRUint32 i,
|
||||
void *arg)
|
||||
{
|
||||
if (heh) {
|
||||
PrefHashEntry *entry = static_cast<PrefHashEntry *>(heh);
|
||||
PrefTuple *newEntry =
|
||||
static_cast<nsTArray<PrefTuple> *>(arg)->AppendElement();
|
||||
|
||||
pref_GetTupleFromEntry(entry, newEntry);
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
pref_GetTupleFromEntry(PrefHashEntry *aHashEntry, PrefTuple *aTuple)
|
||||
{
|
||||
aTuple->key = aHashEntry->key;
|
||||
|
||||
PrefValue *value = PREF_HAS_USER_VALUE(aHashEntry) ?
|
||||
&(aHashEntry->userPref) : &(aHashEntry->defaultPref);
|
||||
|
||||
switch (aHashEntry->flags & PREF_VALUETYPE_MASK) {
|
||||
case PREF_STRING:
|
||||
aTuple->stringVal = value->stringVal;
|
||||
aTuple->type = PrefTuple::PREF_STRING;
|
||||
return;
|
||||
|
||||
case PREF_INT:
|
||||
aTuple->intVal = value->intVal;
|
||||
aTuple->type = PrefTuple::PREF_INT;
|
||||
return;
|
||||
|
||||
case PREF_BOOL:
|
||||
aTuple->boolVal = !!value->boolVal;
|
||||
aTuple->type = PrefTuple::PREF_BOOL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pref_CompareStrings(const void *v1, const void *v2, void *unused)
|
||||
{
|
||||
|
|
|
@ -40,6 +40,8 @@
|
|||
extern PLDHashTable gHashTable;
|
||||
extern PRBool gDirty;
|
||||
|
||||
struct PrefTuple;
|
||||
|
||||
enum pref_SaveTypes { SAVE_NONSHARED, SAVE_SHARED, SAVE_ALL, SAVE_ALL_AND_DEFAULTS };
|
||||
|
||||
// Passed as the arg to pref_savePref
|
||||
|
@ -51,5 +53,13 @@ struct pref_saveArgs {
|
|||
PLDHashOperator
|
||||
pref_savePref(PLDHashTable *table, PLDHashEntryHdr *heh, PRUint32 i, void *arg);
|
||||
|
||||
PLDHashOperator
|
||||
pref_MirrorPrefs(PLDHashTable *table, PLDHashEntryHdr *heh, PRUint32 i, void *arg);
|
||||
|
||||
nsresult
|
||||
pref_SetPrefTuple(const PrefTuple &aPref,PRBool set_default = PR_FALSE);
|
||||
|
||||
int pref_CompareStrings(const void *v1, const void *v2, void* unused);
|
||||
PrefHashEntry* pref_HashTableLookup(const void *key);
|
||||
|
||||
void pref_GetTupleFromEntry(PrefHashEntry *aHashEntry, PrefTuple *aTuple);
|
||||
|
|
Загрузка…
Ссылка в новой задаче