i3 - improved tiling WM


Implement shmlog command

Patch status: merged

Patch by Alexander Berntsen

Long description:

Add shmlog command that takes <size>|toggle|on|off. Separate logbuffer
management into open_logbuffer() and close_logbuffer(). Make
t/187-commands-parser.t expect 'shmlog'. Add update_shmlog_atom() to
update the SHMLOG_PATH. Document the shmlog command in userguide.

To apply this patch, use:
curl http://cr.i3wm.org/patch/179/raw.patch | git am

b/docs/userguide

25
@@ -1762,6 +1762,22 @@ stack-limit rows 5
26
 image:stacklimit.png[Container limited to two columns]
27
 ///////////////////////////////////////////////////////////////////////////////
28
 
29
+== Starting/stopping/changing the size of the shm log
30
+
31
+You may start or stop the shm log with +shmlog+, or change the size of the log.
32
+If you pass a size to the shmlog command, it will change the running log's
33
+size, or, if the log is not running, start the log with the provided size. You
34
+may also toggle the log. This is useful if you want to bind the command to a
35
+key.
36
+
37
+*Examples*:
38
+---------------
39
+shmlog 26214400
40
+shmlog toggle
41
+shmlog on
42
+shmlog off
43
+---------------
44
+
45
 === Reloading/Restarting/Exiting
46
 
47
 You can make i3 reload its configuration file with +reload+. You can also

b/include/commands.h

52
@@ -271,4 +271,10 @@ void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name);
53
  */
54
 void cmd_bar(I3_CMD, char *bar_type, char *bar_value, char *bar_id);
55
 
56
+/*
57
+ * Implementation of 'shmlog <size>|toggle|on|off'
58
+ *
59
+ */
60
+void cmd_shmlog(I3_CMD, char *argument);
61
+
62
 #endif

b/include/log.h

67
@@ -39,6 +39,18 @@ extern int shmlog_size;
68
 void init_logging(void);
69
 
70
 /**
71
+ * Opens the logbuffer.
72
+ *
73
+ */
74
+void open_logbuffer(void);
75
+
76
+/**
77
+ * Closes the logbuffer.
78
+ *
79
+ */
80
+void close_logbuffer(void);
81
+
82
+/**
83
  * Set debug logging.
84
  *
85
  */

b/include/x.h

90
@@ -109,6 +109,12 @@ void x_raise_con(Con *con, bool above_all);
91
 void x_set_name(Con *con, const char *name);
92
 
93
 /**
94
+ * Set up the SHMLOG_PATH atom.
95
+ *
96
+ */
97
+void update_shmlog_atom(void);
98
+
99
+/**
100
  * Sets up i3 specific atoms (I3_SOCKET_PATH and I3_CONFIG_PATH)
101
  *
102
  */

b/parser-specs/commands.spec

107
@@ -19,6 +19,7 @@ state INITIAL:
108
   'exit' -> call cmd_exit()
109
   'restart' -> call cmd_restart()
110
   'reload' -> call cmd_reload()
111
+  'shmlog' -> SHMLOG
112
   'border' -> BORDER
113
   'layout' -> LAYOUT
114
   'append_layout' -> APPEND_LAYOUT
115
@@ -62,6 +63,12 @@ state EXEC:
116
   command = string
117
       -> call cmd_exec($nosn, $command)
118
 
119
+# shmlog <size>|toggle|on|off
120
+state SHMLOG:
121
+  # argument may be a number
122
+  argument = string
123
+    -> call cmd_shmlog($argument)
124
+
125
 # border normal|none|1pixel|toggle|1pixel
126
 state BORDER:
127
   border_style = 'normal', 'pixel'

b/src/commands.c

132
@@ -13,6 +13,7 @@
133
 #include <stdarg.h>
134
 
135
 #include "all.h"
136
+#include "shmlog.h"
137
 
138
 // Macros to make the YAJL API a bit easier to use.
139
 #define y(x, ...) yajl_gen_ ## x (cmd_output->json_gen, ##__VA_ARGS__)
140
@@ -2027,3 +2028,34 @@ void cmd_bar(I3_CMD, char *bar_type, char *bar_value, char *bar_id) {
141
 
142
     update_barconfig();
143
 }
144
+
145
+/*
146
+ * Implementation of 'shmlog <size>|toggle|on|off'
147
+ *
148
+ */
149
+void cmd_shmlog(I3_CMD, char *argument) {
150
+    if (!strcmp(argument,"toggle"))
151
+        /* Toggle shm log, if size is not 0. If it is 0, set it to default. */
152
+        shmlog_size = shmlog_size ? -shmlog_size : default_shmlog_size;
153
+    else if (!strcmp(argument, "on"))
154
+        shmlog_size = default_shmlog_size;
155
+    else if (!strcmp(argument, "off"))
156
+        shmlog_size = 0;
157
+    else {
158
+        /* If shm logging now, restart logging with the new size. */
159
+        if (shmlog_size > 0) {
160
+            shmlog_size = 0;
161
+            LOG("Restarting shm logging...\n");
162
+            init_logging();
163
+        }
164
+        shmlog_size = atoi(argument);
165
+        /* Make a weakly attempt at ensuring the argument is valid. */
166
+        if (shmlog_size <= 0)
167
+            shmlog_size = default_shmlog_size;
168
+    }
169
+    LOG("%s shm logging\n", shmlog_size > 0 ? "Enabling" : "Disabling");
170
+    init_logging();
171
+    update_shmlog_atom();
172
+    // XXX: default reply for now, make this a better reply
173
+    ysuccess(true);
174
+}

b/src/log.c

179
@@ -89,10 +89,21 @@ void init_logging(void) {
180
             }
181
         }
182
     }
183
+    /* Start SHM logging if shmlog_size is > 0. shmlog_size is SHMLOG_SIZE by
184
+     * default on development versions, and 0 on release versions. If it is
185
+     * not > 0, the user has turned it off, so let's close the logbuffer. */
186
+     if (shmlog_size > 0 && logbuffer == NULL)
187
+        open_logbuffer();
188
+     else if (shmlog_size <= 0 && logbuffer)
189
+        close_logbuffer();
190
+     atexit(purge_zerobyte_logfile);
191
+}
192
 
193
-    /* If this is a debug build (not a release version), we will enable SHM
194
-     * logging by default, unless the user turned it off explicitly. */
195
-    if (logbuffer == NULL && shmlog_size > 0) {
196
+/*
197
+ * Opens the logbuffer.
198
+ *
199
+ */
200
+void open_logbuffer(void) {
201
         /* Reserve 1% of the RAM for the logfile, but at max 25 MiB.
202
          * For 512 MiB of RAM this will lead to a 5 MiB log buffer.
203
          * At the moment (2011-12-10), no testcase leads to an i3 log
204
@@ -127,10 +138,8 @@ void init_logging(void) {
205
 
206
         logbuffer = mmap(NULL, logbuffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, logbuffer_shm, 0);
207
         if (logbuffer == MAP_FAILED) {
208
-            close(logbuffer_shm);
209
-            shm_unlink(shmlogname);
210
+            close_logbuffer();
211
             fprintf(stderr, "Could not mmap SHM segment for the i3 log: %s\n", strerror(errno));
212
-            logbuffer = NULL;
213
             return;
214
         }
215
 
216
@@ -148,8 +157,16 @@ void init_logging(void) {
217
         logwalk = logbuffer + sizeof(i3_shmlog_header);
218
         loglastwrap = logbuffer + logbuffer_size;
219
         store_log_markers();
220
-    }
221
-    atexit(purge_zerobyte_logfile);
222
+}
223
+
224
+/*
225
+ * Closes the logbuffer.
226
+ *
227
+ */
228
+void close_logbuffer(void) {
229
+    close(logbuffer_shm);
230
+    shm_unlink(shmlogname);
231
+    logbuffer = NULL;
232
 }
233
 
234
 /*

b/src/x.c

239
@@ -1064,6 +1064,16 @@ void x_set_name(Con *con, const char *name) {
240
 }
241
 
242
 /*
243
+ * Set up the I3_SHMLOG_PATH atom.
244
+ *
245
+ */
246
+void update_shmlog_atom() {
247
+    xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root,
248
+            A_I3_SHMLOG_PATH, A_UTF8_STRING, 8,
249
+            strlen(shmlogname), shmlogname);
250
+}
251
+
252
+/*
253
  * Sets up i3 specific atoms (I3_SOCKET_PATH and I3_CONFIG_PATH)
254
  *
255
  */
256
@@ -1075,8 +1085,7 @@ void x_set_i3_atoms(void) {
257
     xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A_I3_PID, XCB_ATOM_CARDINAL, 32, 1, &pid);
258
     xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A_I3_CONFIG_PATH, A_UTF8_STRING, 8,
259
                         strlen(current_configpath), current_configpath);
260
-    xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A_I3_SHMLOG_PATH, A_UTF8_STRING, 8,
261
-                        strlen(shmlogname), shmlogname);
262
+    update_shmlog_atom();
263
 }
264
 
265
 /*

b/testcases/t/187-commands-parser.t

270
@@ -144,7 +144,7 @@ is(parser_calls("\nworkspace test"),
271
 ################################################################################
272
 
273
 is(parser_calls('unknown_literal'),
274
-   "ERROR: Expected one of these tokens: <end>, '[', 'move', 'exec', 'exit', 'restart', 'reload', 'border', 'layout', 'append_layout', 'workspace', 'focus', 'kill', 'open', 'fullscreen', 'split', 'floating', 'mark', 'resize', 'rename', 'nop', 'scratchpad', 'mode', 'bar'\n" .
275
+   "ERROR: Expected one of these tokens: <end>, '[', 'move', 'exec', 'exit', 'restart', 'reload', 'shmlog', 'border', 'layout', 'append_layout', 'workspace', 'focus', 'kill', 'open', 'fullscreen', 'split', 'floating', 'mark', 'resize', 'rename', 'nop', 'scratchpad', 'mode', 'bar'\n" .
276
    "ERROR: Your command: unknown_literal\n" .
277
    "ERROR:               ^^^^^^^^^^^^^^^",
278
    'error for unknown literal ok');