summaryrefslogtreecommitdiff
path: root/vala
diff options
context:
space:
mode:
authorJiří Zárevúcky <zarevucky.jiri@gmail.com>2010-03-24 08:36:37 +0100
committerJürg Billeter <j@bitron.ch>2010-03-24 08:36:37 +0100
commit40c1dbfbfedb6c4a6b88df045eb1c2e7bdd38d93 (patch)
tree7b3ad670a285f3a4c5687686e23c3ffdc0f06883 /vala
parent30f3bdf5503071f6a4cf6780494f5bddf49d68ed (diff)
downloadvala-40c1dbfbfedb6c4a6b88df045eb1c2e7bdd38d93.tar.gz
Fix lock statement
This patch converts lock statements into try finally statements to ensure that unlock is always called. Fixes bug 582553.
Diffstat (limited to 'vala')
-rw-r--r--vala/Makefile.am1
-rw-r--r--vala/valacodevisitor.vala8
-rw-r--r--vala/valaflowanalyzer.vala6
-rw-r--r--vala/valalockstatement.vala39
-rw-r--r--vala/valaunlockstatement.vala70
5 files changed, 115 insertions, 9 deletions
diff --git a/vala/Makefile.am b/vala/Makefile.am
index 69f0d0ac6..aa0b861f4 100644
--- a/vala/Makefile.am
+++ b/vala/Makefile.am
@@ -151,6 +151,7 @@ libvalacore_la_VALASOURCES = \
valatypeparameter.vala \
valatypesymbol.vala \
valaunaryexpression.vala \
+ valaunlockstatement.vala \
valaunresolvedsymbol.vala \
valaunresolvedtype.vala \
valausingdirective.vala \
diff --git a/vala/valacodevisitor.vala b/vala/valacodevisitor.vala
index f11a3ef43..55f87d7cc 100644
--- a/vala/valacodevisitor.vala
+++ b/vala/valacodevisitor.vala
@@ -405,6 +405,14 @@ public abstract class Vala.CodeVisitor {
}
/**
+ * Visit operation called for unlock statements.
+ *
+ * @param stmt an unlock statement
+ */
+ public virtual void visit_unlock_statement (UnlockStatement stmt) {
+ }
+
+ /**
* Visit operation called for delete statements.
*
* @param stmt a delete statement
diff --git a/vala/valaflowanalyzer.vala b/vala/valaflowanalyzer.vala
index ff5f255db..193f6103a 100644
--- a/vala/valaflowanalyzer.vala
+++ b/vala/valaflowanalyzer.vala
@@ -1010,8 +1010,12 @@ public class Vala.FlowAnalyzer : CodeVisitor {
if (unreachable (stmt)) {
return;
}
+ }
- stmt.body.accept (this);
+ public override void visit_unlock_statement (UnlockStatement stmt) {
+ if (unreachable (stmt)) {
+ return;
+ }
}
public override void visit_expression (Expression expr) {
diff --git a/vala/valalockstatement.vala b/vala/valalockstatement.vala
index 9ad5dfbdd..da9a0be94 100644
--- a/vala/valalockstatement.vala
+++ b/vala/valalockstatement.vala
@@ -1,5 +1,6 @@
/* valalockstatement.vala
*
+ * Copyright (C) 2009 Jiří Zárevúcky
* Copyright (C) 2006-2007 Raffaele Sandrini, Jürg Billeter
*
* This library is free software; you can redistribute it and/or
@@ -16,14 +17,19 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
- * Author:
+ * Authors:
* Raffaele Sandrini <raffaele@sandrini.ch>
+ * Jiří Zárevúcky <zarevucky.jiri@gmail.com>
*/
using GLib;
/**
- * Represents a lock statement e.g. {{{ lock (a) { f(a) } }}}.
+ * Represents a lock statement e.g. {{{ lock (a); }}} or {{{ lock (a) { f(a); } }}}.
+ *
+ * If the statement is empty, the mutex remains locked until a corresponding UnlockStatement
+ * occurs. Otherwise it's translated into a try/finally statement which unlocks the mutex
+ * after the block is finished.
*/
public class Vala.LockStatement : CodeNode, Statement {
/**
@@ -34,9 +40,9 @@ public class Vala.LockStatement : CodeNode, Statement {
/**
* The statement during its execution the resource is locked.
*/
- public Block body { get; set; }
+ public Block? body { get; set; }
- public LockStatement (Expression resource, Block body, SourceReference? source_reference = null) {
+ public LockStatement (Expression resource, Block? body, SourceReference? source_reference = null) {
this.body = body;
this.source_reference = source_reference;
this.resource = resource;
@@ -44,11 +50,29 @@ public class Vala.LockStatement : CodeNode, Statement {
public override void accept (CodeVisitor visitor) {
resource.accept (visitor);
- body.accept (visitor);
+ if (body != null) {
+ body.accept (visitor);
+ }
visitor.visit_lock_statement (this);
}
public override bool check (SemanticAnalyzer analyzer) {
+ if (body != null) {
+ // if the statement isn't empty, it is converted into a try statement
+
+ var fin_body = new Block (source_reference);
+ fin_body.add_statement (new UnlockStatement (resource, source_reference));
+
+ var block = new Block (source_reference);
+ block.add_statement (new LockStatement (resource, null, source_reference));
+ block.add_statement (new TryStatement (body, fin_body, source_reference));
+
+ var parent_block = (Block) parent_node;
+ parent_block.replace_statement (this, block);
+
+ return block.check (analyzer);
+ }
+
if (checked) {
return !error;
}
@@ -56,11 +80,10 @@ public class Vala.LockStatement : CodeNode, Statement {
checked = true;
resource.check (analyzer);
- body.check (analyzer);
/* resource must be a member access and denote a Lockable */
if (!(resource is MemberAccess && resource.symbol_reference is Lockable)) {
- error = true;
+ error = true;
resource.error = true;
Report.error (resource.source_reference, "Expression is either not a member access or does not denote a lockable member");
return false;
@@ -68,7 +91,7 @@ public class Vala.LockStatement : CodeNode, Statement {
/* parent symbol must be the current class */
if (resource.symbol_reference.parent_symbol != analyzer.current_class) {
- error = true;
+ error = true;
resource.error = true;
Report.error (resource.source_reference, "Only members of the current class are lockable");
}
diff --git a/vala/valaunlockstatement.vala b/vala/valaunlockstatement.vala
new file mode 100644
index 000000000..e0ae1a034
--- /dev/null
+++ b/vala/valaunlockstatement.vala
@@ -0,0 +1,70 @@
+/* valaunlockstatement.vala
+ *
+ * Copyright (C) 2009 Jiří Zárevúcky, Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Jiří Zárevúcky <zarevucky.jiri@gmail.com>
+ */
+
+/**
+ * Represents an unlock statement e.g. {{{ unlock (a); }}}.
+ */
+public class Vala.UnlockStatement : CodeNode, Statement {
+ /**
+ * Expression representing the resource to be unlocked.
+ */
+ public Expression resource { get; set; }
+
+ public UnlockStatement (Expression resource, SourceReference? source_reference = null) {
+ this.source_reference = source_reference;
+ this.resource = resource;
+ }
+
+ public override void accept (CodeVisitor visitor) {
+ resource.accept (visitor);
+ visitor.visit_unlock_statement (this);
+ }
+
+ public override bool check (SemanticAnalyzer analyzer) {
+ if (checked) {
+ return !error;
+ }
+
+ checked = true;
+
+ resource.check (analyzer);
+
+ /* resource must be a member access and denote a Lockable */
+ if (!(resource is MemberAccess && resource.symbol_reference is Lockable)) {
+ error = true;
+ resource.error = true;
+ Report.error (resource.source_reference, "Expression is either not a member access or does not denote a lockable member");
+ return false;
+ }
+
+ /* parent symbol must be the current class */
+ if (resource.symbol_reference.parent_symbol != analyzer.current_class) {
+ error = true;
+ resource.error = true;
+ Report.error (resource.source_reference, "Only members of the current class are lockable");
+ }
+
+ ((Lockable) resource.symbol_reference).set_lock_used (true);
+
+ return !error;
+ }
+}