2012-01-10 10:40:34 -08:00
|
|
|
/* Copyright 2011-2012 Yorba Foundation
|
2011-06-28 16:33:27 -07:00
|
|
|
*
|
|
|
|
|
* This software is licensed under the GNU Lesser General Public License
|
|
|
|
|
* (version 2.1 or later). See the COPYING file in this distribution.
|
|
|
|
|
*/
|
|
|
|
|
|
2011-07-29 20:10:43 -07:00
|
|
|
public abstract class Geary.NonblockingAbstractSemaphore {
|
2011-06-28 16:33:27 -07:00
|
|
|
private class Pending {
|
2011-09-26 16:07:40 -07:00
|
|
|
public unowned SourceFunc cb;
|
2011-07-01 15:40:20 -07:00
|
|
|
public Cancellable? cancellable;
|
2011-07-29 20:10:43 -07:00
|
|
|
public bool passed = false;
|
2011-10-06 19:00:13 -07:00
|
|
|
public bool scheduled = false;
|
2011-06-28 16:33:27 -07:00
|
|
|
|
2011-07-01 15:40:20 -07:00
|
|
|
public signal void cancelled();
|
|
|
|
|
|
|
|
|
|
public Pending(SourceFunc cb, Cancellable? cancellable) {
|
2011-06-28 16:33:27 -07:00
|
|
|
this.cb = cb;
|
2011-07-01 15:40:20 -07:00
|
|
|
this.cancellable = cancellable;
|
|
|
|
|
|
|
|
|
|
if (cancellable != null)
|
|
|
|
|
cancellable.cancelled.connect(on_cancelled);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~Pending() {
|
|
|
|
|
if (cancellable != null)
|
|
|
|
|
cancellable.cancelled.disconnect(on_cancelled);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void on_cancelled() {
|
|
|
|
|
cancelled();
|
2011-06-28 16:33:27 -07:00
|
|
|
}
|
2011-10-06 19:00:13 -07:00
|
|
|
|
|
|
|
|
public void schedule(bool passed) {
|
|
|
|
|
assert(!scheduled);
|
|
|
|
|
|
|
|
|
|
this.passed = passed;
|
|
|
|
|
|
|
|
|
|
Scheduler.on_idle(cb);
|
|
|
|
|
scheduled = true;
|
|
|
|
|
}
|
2011-06-28 16:33:27 -07:00
|
|
|
}
|
|
|
|
|
|
2011-07-01 15:40:20 -07:00
|
|
|
private bool broadcast;
|
2011-07-29 20:10:43 -07:00
|
|
|
private bool autoreset;
|
2011-06-28 16:33:27 -07:00
|
|
|
private Cancellable? cancellable;
|
|
|
|
|
private bool passed = false;
|
|
|
|
|
private Gee.List<Pending> pending_queue = new Gee.LinkedList<Pending>();
|
|
|
|
|
|
2012-09-13 16:17:58 -07:00
|
|
|
public virtual signal void at_reset() {
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-29 20:10:43 -07:00
|
|
|
protected NonblockingAbstractSemaphore(bool broadcast, bool autoreset, Cancellable? cancellable = null) {
|
2011-07-01 15:40:20 -07:00
|
|
|
this.broadcast = broadcast;
|
2011-07-29 20:10:43 -07:00
|
|
|
this.autoreset = autoreset;
|
2011-06-28 16:33:27 -07:00
|
|
|
this.cancellable = cancellable;
|
|
|
|
|
|
|
|
|
|
if (cancellable != null)
|
|
|
|
|
cancellable.cancelled.connect(on_cancelled);
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-29 20:10:43 -07:00
|
|
|
~NonblockingAbstractSemaphore() {
|
Remove SQLHeavy: Closes #5034
It is done.
Initial implementation of the new database subsystem
These pieces represent the foundation for ticket #5034
Expanded transactions, added VersionedDatabase
Further expansions of the async code.
Moved async pool logic into Database, where it realistically
belongs.
Further improvements. Introduced geary-db-test.
Added SQL create and update files for Geary.Db
version-001 to version-003 are exact copies of the SQLHeavy scripts
to ensure no slight changes when migrating. version-004 upgrades
the database to remove the ImapFolderPropertiesTable and
ImapMessagePropertiesTable, now that the database code is pure
IMAP.
When we support other messaging systems (such as POP3), those
subsystems will need to code their own database layers OR rely on
the IMAP schema and simply ignore the IMAP-specific fields.
ImapDB.Account fleshed out
ImapDB.Folder is commented out, however. Need to port next.
ImapDB.Folder fleshed out
MessageTable, MessageLocationTable, and AttachementTable are now
handled inside ImapDB.Folder.
chmod -x imap-db-database.vala
OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties
Moved SmtpOutboxFolderRoot into its own source file
SmtpOutboxFolder ported to new database code
Move Engine implementations to ImapDB.
Integration and cleanup of new database code with main source
This commit performs the final integration steps to move Geary
completely over to the new database model. This also cleans out
the old SQLHeavy-based code and fixes a handful of small bugs that
were detected during basic test runs.
Moved Outbox to ImapDB
As the Outbox is tied to the database that ImapDB runs, move the
Outbox code into that folder.
Outbox fixes and better parameter checking
Bumped Database thread pool count and made them exclusive
My reasoning is that there may be a need for a lot of threads at
once (when a big batch of commands comes in, especially at
startup). If performance looks ok, we might consider relaxing
this later.
2012-06-14 14:47:53 -07:00
|
|
|
if (pending_queue.size > 0) {
|
2011-06-28 16:33:27 -07:00
|
|
|
warning("Nonblocking semaphore destroyed with %d pending callers", pending_queue.size);
|
Remove SQLHeavy: Closes #5034
It is done.
Initial implementation of the new database subsystem
These pieces represent the foundation for ticket #5034
Expanded transactions, added VersionedDatabase
Further expansions of the async code.
Moved async pool logic into Database, where it realistically
belongs.
Further improvements. Introduced geary-db-test.
Added SQL create and update files for Geary.Db
version-001 to version-003 are exact copies of the SQLHeavy scripts
to ensure no slight changes when migrating. version-004 upgrades
the database to remove the ImapFolderPropertiesTable and
ImapMessagePropertiesTable, now that the database code is pure
IMAP.
When we support other messaging systems (such as POP3), those
subsystems will need to code their own database layers OR rely on
the IMAP schema and simply ignore the IMAP-specific fields.
ImapDB.Account fleshed out
ImapDB.Folder is commented out, however. Need to port next.
ImapDB.Folder fleshed out
MessageTable, MessageLocationTable, and AttachementTable are now
handled inside ImapDB.Folder.
chmod -x imap-db-database.vala
OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties
Moved SmtpOutboxFolderRoot into its own source file
SmtpOutboxFolder ported to new database code
Move Engine implementations to ImapDB.
Integration and cleanup of new database code with main source
This commit performs the final integration steps to move Geary
completely over to the new database model. This also cleans out
the old SQLHeavy-based code and fixes a handful of small bugs that
were detected during basic test runs.
Moved Outbox to ImapDB
As the Outbox is tied to the database that ImapDB runs, move the
Outbox code into that folder.
Outbox fixes and better parameter checking
Bumped Database thread pool count and made them exclusive
My reasoning is that there may be a need for a lot of threads at
once (when a big batch of commands comes in, especially at
startup). If performance looks ok, we might consider relaxing
this later.
2012-06-14 14:47:53 -07:00
|
|
|
|
|
|
|
|
foreach (Pending pending in pending_queue)
|
|
|
|
|
pending.cancelled.disconnect(on_pending_cancelled);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cancellable != null)
|
|
|
|
|
cancellable.cancelled.disconnect(on_cancelled);
|
2011-06-28 16:33:27 -07:00
|
|
|
}
|
|
|
|
|
|
2012-09-13 16:17:58 -07:00
|
|
|
protected virtual void notify_at_reset() {
|
|
|
|
|
at_reset();
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-01 15:40:20 -07:00
|
|
|
private void trigger(bool all) {
|
|
|
|
|
if (pending_queue.size == 0)
|
|
|
|
|
return;
|
2011-06-28 16:33:27 -07:00
|
|
|
|
2011-07-29 20:10:43 -07:00
|
|
|
// in both cases, mark the Pending object(s) as passed in case this is an auto-reset
|
|
|
|
|
// semaphore
|
2011-07-01 15:40:20 -07:00
|
|
|
if (all) {
|
2011-10-06 19:00:13 -07:00
|
|
|
foreach (Pending pending in pending_queue)
|
|
|
|
|
pending.schedule(passed);
|
2011-07-01 15:40:20 -07:00
|
|
|
|
|
|
|
|
pending_queue.clear();
|
|
|
|
|
} else {
|
|
|
|
|
Pending pending = pending_queue.remove_at(0);
|
2011-10-06 19:00:13 -07:00
|
|
|
pending.schedule(passed);
|
2011-07-01 15:40:20 -07:00
|
|
|
}
|
2011-06-28 16:33:27 -07:00
|
|
|
}
|
|
|
|
|
|
2012-09-13 16:17:58 -07:00
|
|
|
public virtual void notify() throws Error {
|
2011-06-28 16:33:27 -07:00
|
|
|
check_cancelled();
|
|
|
|
|
|
|
|
|
|
passed = true;
|
2011-07-01 15:40:20 -07:00
|
|
|
|
|
|
|
|
trigger(broadcast);
|
2011-07-29 20:10:43 -07:00
|
|
|
|
|
|
|
|
if (autoreset)
|
|
|
|
|
reset();
|
2011-06-28 16:33:27 -07:00
|
|
|
}
|
|
|
|
|
|
2012-06-06 16:36:52 -07:00
|
|
|
/**
|
|
|
|
|
* Calls notify() without throwing an Exception, which is merely logged if encountered.
|
|
|
|
|
*/
|
|
|
|
|
public void blind_notify() {
|
|
|
|
|
try {
|
|
|
|
|
notify();
|
|
|
|
|
} catch (Error err) {
|
|
|
|
|
message("Error notifying semaphore: %s", err.message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-13 16:17:58 -07:00
|
|
|
public virtual async void wait_async(Cancellable? cancellable = null) throws Error {
|
2011-06-28 16:33:27 -07:00
|
|
|
for (;;) {
|
2011-07-01 15:40:20 -07:00
|
|
|
check_user_cancelled(cancellable);
|
2011-06-28 16:33:27 -07:00
|
|
|
check_cancelled();
|
|
|
|
|
|
|
|
|
|
if (passed)
|
|
|
|
|
return;
|
|
|
|
|
|
2011-07-01 15:40:20 -07:00
|
|
|
Pending pending = new Pending(wait_async.callback, cancellable);
|
|
|
|
|
pending.cancelled.connect(on_pending_cancelled);
|
|
|
|
|
|
|
|
|
|
pending_queue.add(pending);
|
2011-06-28 16:33:27 -07:00
|
|
|
yield;
|
2011-07-01 15:40:20 -07:00
|
|
|
|
|
|
|
|
pending.cancelled.disconnect(on_pending_cancelled);
|
2011-07-29 20:10:43 -07:00
|
|
|
|
2011-10-12 16:46:23 -07:00
|
|
|
if (pending.passed) {
|
|
|
|
|
check_user_cancelled(cancellable);
|
|
|
|
|
|
2011-07-29 20:10:43 -07:00
|
|
|
return;
|
2011-10-12 16:46:23 -07:00
|
|
|
}
|
2011-06-28 16:33:27 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-13 16:17:58 -07:00
|
|
|
public virtual void reset() {
|
2012-09-17 14:49:54 -07:00
|
|
|
if (!passed)
|
|
|
|
|
return;
|
|
|
|
|
|
2011-07-01 15:40:20 -07:00
|
|
|
passed = false;
|
2012-09-13 16:17:58 -07:00
|
|
|
|
|
|
|
|
notify_at_reset();
|
2011-07-01 15:40:20 -07:00
|
|
|
}
|
|
|
|
|
|
2013-02-25 20:18:37 -08:00
|
|
|
public bool is_passed() {
|
|
|
|
|
return passed;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-28 16:33:27 -07:00
|
|
|
public bool is_cancelled() {
|
|
|
|
|
return (cancellable != null) ? cancellable.is_cancelled() : false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void check_cancelled() throws Error {
|
|
|
|
|
if (is_cancelled())
|
|
|
|
|
throw new IOError.CANCELLED("Semaphore cancelled");
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-01 15:40:20 -07:00
|
|
|
private static void check_user_cancelled(Cancellable? cancellable) throws Error {
|
|
|
|
|
if (cancellable != null && cancellable.is_cancelled())
|
|
|
|
|
throw new IOError.CANCELLED("User cancelled operation");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void on_pending_cancelled(Pending pending) {
|
2011-10-06 19:00:13 -07:00
|
|
|
// if already scheduled, the cancellation will be dealt with when they wake up
|
|
|
|
|
if (pending.scheduled)
|
|
|
|
|
return;
|
|
|
|
|
|
2011-07-01 15:40:20 -07:00
|
|
|
bool removed = pending_queue.remove(pending);
|
|
|
|
|
assert(removed);
|
|
|
|
|
|
2011-09-26 16:07:40 -07:00
|
|
|
Scheduler.on_idle(pending.cb);
|
2011-07-01 15:40:20 -07:00
|
|
|
}
|
|
|
|
|
|
2011-06-28 16:33:27 -07:00
|
|
|
private void on_cancelled() {
|
2011-07-01 15:40:20 -07:00
|
|
|
trigger(true);
|
2011-06-28 16:33:27 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|