summaryrefslogtreecommitdiffstats
path: root/WebCore/page/GeolocationPositionCache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/page/GeolocationPositionCache.cpp')
-rw-r--r--WebCore/page/GeolocationPositionCache.cpp169
1 files changed, 124 insertions, 45 deletions
diff --git a/WebCore/page/GeolocationPositionCache.cpp b/WebCore/page/GeolocationPositionCache.cpp
index 06159f4..4a9c6b7 100644
--- a/WebCore/page/GeolocationPositionCache.cpp
+++ b/WebCore/page/GeolocationPositionCache.cpp
@@ -28,64 +28,118 @@
#if ENABLE(GEOLOCATION)
+#include "CrossThreadTask.h"
#include "Geoposition.h"
#include "SQLValue.h"
#include "SQLiteDatabase.h"
#include "SQLiteFileSystem.h"
#include "SQLiteStatement.h"
#include "SQLiteTransaction.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Threading.h>
+
+using namespace WTF;
namespace WebCore {
-static const char* databaseName = "CachedGeoposition.db";
+static int numUsers = 0;
-int GeolocationPositionCache::s_instances = 0;
-RefPtr<Geoposition>* GeolocationPositionCache::s_cachedPosition;
-String* GeolocationPositionCache::s_databaseFile = 0;
+GeolocationPositionCache* GeolocationPositionCache::instance()
+{
+ DEFINE_STATIC_LOCAL(GeolocationPositionCache*, instance, (0));
+ if (!instance)
+ instance = new GeolocationPositionCache();
+ return instance;
+}
GeolocationPositionCache::GeolocationPositionCache()
+ : m_threadId(0)
+{
+}
+
+void GeolocationPositionCache::addUser()
{
- if (!(s_instances++)) {
- s_cachedPosition = new RefPtr<Geoposition>;
- *s_cachedPosition = readFromDB();
+ ASSERT(numUsers >= 0);
+ if (!numUsers && !m_threadId) {
+ startBackgroundThread();
+ MutexLocker lock(m_cachedPositionMutex);
+ if (!m_cachedPosition)
+ triggerReadFromDatabase();
}
+ ++numUsers;
}
-GeolocationPositionCache::~GeolocationPositionCache()
+void GeolocationPositionCache::removeUser()
{
- if (!(--s_instances)) {
- if (*s_cachedPosition)
- writeToDB(s_cachedPosition->get());
- delete s_cachedPosition;
+ MutexLocker lock(m_cachedPositionMutex);
+ --numUsers;
+ ASSERT(numUsers >= 0);
+ if (!numUsers && m_cachedPosition)
+ triggerWriteToDatabase();
+}
+
+void GeolocationPositionCache::setDatabasePath(const String& path)
+{
+ static const char* databaseName = "CachedGeoposition.db";
+ String newFile = SQLiteFileSystem::appendDatabaseFileNameToPath(path, databaseName);
+ MutexLocker lock(m_databaseFileMutex);
+ if (m_databaseFile != newFile) {
+ m_databaseFile = newFile;
+ if (numUsers && !m_cachedPosition)
+ triggerReadFromDatabase();
}
}
void GeolocationPositionCache::setCachedPosition(Geoposition* cachedPosition)
{
- *s_cachedPosition = cachedPosition;
+ MutexLocker lock(m_cachedPositionMutex);
+ m_cachedPosition = cachedPosition;
}
Geoposition* GeolocationPositionCache::cachedPosition()
{
- return s_cachedPosition->get();
+ MutexLocker lock(m_cachedPositionMutex);
+ return m_cachedPosition.get();
+}
+
+void GeolocationPositionCache::startBackgroundThread()
+{
+ // FIXME: Consider sharing this thread with other background tasks.
+ m_threadId = createThread(threadEntryPoint, this, "WebCore: GeolocationPositionCache");
+}
+
+void* GeolocationPositionCache::threadEntryPoint(void* object)
+{
+ static_cast<GeolocationPositionCache*>(object)->threadEntryPointImpl();
+ return 0;
+}
+
+void GeolocationPositionCache::threadEntryPointImpl()
+{
+ while (OwnPtr<ScriptExecutionContext::Task> task = m_queue.waitForMessage()) {
+ // We don't need a ScriptExecutionContext in the callback, so pass 0 here.
+ task->performTask(0);
+ }
+}
+
+void GeolocationPositionCache::triggerReadFromDatabase()
+{
+ m_queue.append(createCallbackTask(&GeolocationPositionCache::readFromDatabase, this));
}
-void GeolocationPositionCache::setDatabasePath(const String& databasePath)
+void GeolocationPositionCache::readFromDatabase(ScriptExecutionContext*, GeolocationPositionCache* cache)
{
- if (!s_databaseFile)
- s_databaseFile = new String;
- *s_databaseFile = SQLiteFileSystem::appendDatabaseFileNameToPath(databasePath, databaseName);
- // If we don't have have a cached position, attempt to read one from the
- // DB at the new path.
- if (s_instances && !(*s_cachedPosition))
- *s_cachedPosition = readFromDB();
+ cache->readFromDatabaseImpl();
}
-PassRefPtr<Geoposition> GeolocationPositionCache::readFromDB()
+void GeolocationPositionCache::readFromDatabaseImpl()
{
SQLiteDatabase database;
- if (!s_databaseFile || !database.open(*s_databaseFile))
- return 0;
+ {
+ MutexLocker lock(m_databaseFileMutex);
+ if (!database.open(m_databaseFile))
+ return;
+ }
// Create the table here, such that even if we've just created the
// DB, the commands below should succeed.
@@ -98,14 +152,14 @@ PassRefPtr<Geoposition> GeolocationPositionCache::readFromDB()
"heading REAL, "
"speed REAL, "
"timestamp INTEGER NOT NULL)"))
- return 0;
+ return;
SQLiteStatement statement(database, "SELECT * FROM CachedPosition");
if (statement.prepare() != SQLResultOk)
- return 0;
+ return;
if (statement.step() != SQLResultRow)
- return 0;
+ return;
bool providesAltitude = statement.getColumnValue(2).type() != SQLValue::NullValue;
bool providesAltitudeAccuracy = statement.getColumnValue(4).type() != SQLValue::NullValue;
@@ -118,16 +172,40 @@ PassRefPtr<Geoposition> GeolocationPositionCache::readFromDB()
providesAltitudeAccuracy, statement.getColumnDouble(4), // altitudeAccuracy
providesHeading, statement.getColumnDouble(5), // heading
providesSpeed, statement.getColumnDouble(6)); // speed
- return Geoposition::create(coordinates.release(), statement.getColumnInt64(7)); // timestamp
+ DOMTimeStamp timestamp = statement.getColumnInt64(7); // timestamp
+
+ // A position may have been set since we called triggerReadFromDatabase().
+ MutexLocker lock(m_cachedPositionMutex);
+ if (m_cachedPosition)
+ return;
+ m_cachedPosition = Geoposition::create(coordinates.release(), timestamp);
}
-void GeolocationPositionCache::writeToDB(const Geoposition* position)
+void GeolocationPositionCache::triggerWriteToDatabase()
{
- ASSERT(position);
+ m_queue.append(createCallbackTask(writeToDatabase, this));
+}
+void GeolocationPositionCache::writeToDatabase(ScriptExecutionContext*, GeolocationPositionCache* cache)
+{
+ cache->writeToDatabaseImpl();
+}
+
+void GeolocationPositionCache::writeToDatabaseImpl()
+{
SQLiteDatabase database;
- if (!s_databaseFile || !database.open(*s_databaseFile))
- return;
+ {
+ MutexLocker lock(m_databaseFileMutex);
+ if (!database.open(m_databaseFile))
+ return;
+ }
+
+ RefPtr<Geoposition> cachedPosition;
+ {
+ MutexLocker lock(m_cachedPositionMutex);
+ if (m_cachedPosition)
+ cachedPosition = m_cachedPosition->threadSafeCopy();
+ }
SQLiteTransaction transaction(database);
@@ -147,26 +225,27 @@ void GeolocationPositionCache::writeToDB(const Geoposition* position)
if (statement.prepare() != SQLResultOk)
return;
- statement.bindDouble(1, position->coords()->latitude());
- statement.bindDouble(2, position->coords()->longitude());
- if (position->coords()->canProvideAltitude())
- statement.bindDouble(3, position->coords()->altitude());
+ statement.bindDouble(1, cachedPosition->coords()->latitude());
+ statement.bindDouble(2, cachedPosition->coords()->longitude());
+ if (cachedPosition->coords()->canProvideAltitude())
+ statement.bindDouble(3, cachedPosition->coords()->altitude());
else
statement.bindNull(3);
- statement.bindDouble(4, position->coords()->accuracy());
- if (position->coords()->canProvideAltitudeAccuracy())
- statement.bindDouble(5, position->coords()->altitudeAccuracy());
+ statement.bindDouble(4, cachedPosition->coords()->accuracy());
+ if (cachedPosition->coords()->canProvideAltitudeAccuracy())
+ statement.bindDouble(5, cachedPosition->coords()->altitudeAccuracy());
else
statement.bindNull(5);
- if (position->coords()->canProvideHeading())
- statement.bindDouble(6, position->coords()->heading());
+ if (cachedPosition->coords()->canProvideHeading())
+ statement.bindDouble(6, cachedPosition->coords()->heading());
else
statement.bindNull(6);
- if (position->coords()->canProvideSpeed())
- statement.bindDouble(7, position->coords()->speed());
+ if (cachedPosition->coords()->canProvideSpeed())
+ statement.bindDouble(7, cachedPosition->coords()->speed());
else
statement.bindNull(7);
- statement.bindInt64(8, position->timestamp());
+ statement.bindInt64(8, cachedPosition->timestamp());
+
if (!statement.executeCommand())
return;