summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.zig15
-rw-r--r--exercises/093_async10.zig67
-rw-r--r--patches/patches/093_async10.patch13
3 files changed, 91 insertions, 4 deletions
diff --git a/build.zig b/build.zig
index 5e5d3de..b9aaac3 100644
--- a/build.zig
+++ b/build.zig
@@ -1161,13 +1161,20 @@ const exercises = [_]Exercise{
},
.{
.main_file = "092_async9.zig",
- .output = "",
- .skip = true,
+ .output =
+ \\Main thread continues...
+ \\Computing on a separate thread!
+ \\Main thread done waiting.
+ \\Result: 123
+ , // pay attention to the comma
},
.{
.main_file = "093_async10.zig",
- .output = "",
- .skip = true,
+ .output =
+ \\Starting critical section...
+ \\Critical section completed safely.
+ \\Task result: All data saved.
+ , // pay attention to the comma
},
.{
.main_file = "094_async_quiz.zig",
diff --git a/exercises/093_async10.zig b/exercises/093_async10.zig
new file mode 100644
index 0000000..6ed229d
--- /dev/null
+++ b/exercises/093_async10.zig
@@ -0,0 +1,67 @@
+//
+// In exercise 088, we learned that cancellation happens at
+// "cancellation points" — any Io function that can return
+// error.Canceled.
+//
+// But sometimes a task has a critical section that MUST NOT
+// be interrupted — for example, writing a consistent state
+// to disk, or completing a transaction.
+//
+// Io provides CancelProtection for this:
+//
+// const old = io.swapCancelProtection(.blocked);
+// defer _ = io.swapCancelProtection(old);
+//
+// // In this block, NO Io function will return error.Canceled.
+// // The cancel request is held until protection is restored.
+//
+// There are two states:
+// .unblocked — normal: cancellation points can fire (default)
+// .blocked — protected: error.Canceled is never returned
+//
+// There's also io.checkCancel() — a pure cancellation point
+// that does nothing except return error.Canceled if a cancel
+// request is pending. Useful in long CPU-bound loops.
+//
+// And io.recancel() — re-arms a consumed cancel request so
+// the NEXT cancellation point will fire again.
+//
+// Fix this program so the critical section completes even
+// when the task is canceled.
+//
+const std = @import("std");
+const print = std.debug.print;
+
+pub fn main(init: std.process.Init) !void {
+ const io = init.io;
+
+ var future = io.async(importantTask, .{io});
+
+ // Give the task time to start and enter its critical section.
+ io.sleep(std.Io.Duration.fromMilliseconds(300), .awake) catch {};
+
+ // Cancel while the task is in its protected section.
+ const result = future.cancel(io);
+ print("Task result: {s}\n", .{result});
+}
+
+fn importantTask(io: std.Io) []const u8 {
+ print("Starting critical section...\n", .{});
+
+ // Protect this section from cancellation.
+ // What method swaps the cancel protection state?
+ const old = io.???(. blocked);
+ defer _ = io.???(old);
+
+ // This sleep will NOT return error.Canceled even though
+ // we get canceled during it — protection is active!
+ io.sleep(std.Io.Duration.fromMilliseconds(600), .awake) catch |err| switch (err) {
+ error.Canceled => {
+ // This should never happen while protected!
+ return "ERROR: canceled during critical section!";
+ },
+ };
+
+ print("Critical section completed safely.\n", .{});
+ return "All data saved.";
+}
diff --git a/patches/patches/093_async10.patch b/patches/patches/093_async10.patch
new file mode 100644
index 0000000..69f7518
--- /dev/null
+++ b/patches/patches/093_async10.patch
@@ -0,0 +1,13 @@
+--- exercises/093_async10.zig 2026-04-03 14:25:16.600025924 +0200
++++ answers/093_async10.zig 2026-04-03 14:24:56.192615893 +0200
+@@ -50,8 +50,8 @@
+
+ // Protect this section from cancellation.
+ // What method swaps the cancel protection state?
+- const old = io.???(. blocked);
+- defer _ = io.???(old);
++ const old = io.swapCancelProtection(.blocked);
++ defer _ = io.swapCancelProtection(old);
+
+ // This sleep will NOT return error.Canceled even though
+ // we get canceled during it — protection is active!