i3 - improved tiling WM


Implement shmlog command

Patch status: needinfo

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.

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

b/include/commands.h

24
@@ -271,4 +271,10 @@ void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name);
25
  */
26
 void cmd_bar(I3_CMD, char *bar_type, char *bar_value, char *bar_id);
27
 
28
+/*
29
+ * Implementation of 'shmlog <size>|toggle|on|off'
30
+ *
31
+ */
32
+void cmd_shmlog(I3_CMD, char *argument);
33
+
34
 #endif

b/include/log.h

39
@@ -39,6 +39,18 @@ extern int shmlog_size;
40
 void init_logging(void);
41
 
42
 /**
43
+ * Opens the logbuffer.
44
+ *
45
+ */
46
+void open_logbuffer(void);
47
+
48
+/**
49
+ * Closes the logbuffer.
50
+ *
51
+ */
52
+void close_logbuffer(void);
53
+
54
+/**
55
  * Set debug logging.
56
  *
57
  */

b/include/x.h

62
@@ -109,6 +109,12 @@ void x_raise_con(Con *con, bool above_all);
63
 void x_set_name(Con *con, const char *name);
64
 
65
 /**
66
+ * Set up the SHMLOG_PATH atom.
67
+ *
68
+ */
69
+void update_shmlog_atom(void);
70
+
71
+/**
72
  * Sets up i3 specific atoms (I3_SOCKET_PATH and I3_CONFIG_PATH)
73
  *
74
  */

b/parser-specs/commands.spec

79
@@ -19,6 +19,7 @@ state INITIAL:
80
   'exit' -> call cmd_exit()
81
   'restart' -> call cmd_restart()
82
   'reload' -> call cmd_reload()
83
+  'shmlog' -> SHMLOG
84
   'border' -> BORDER
85
   'layout' -> LAYOUT
86
   'append_layout' -> APPEND_LAYOUT
87
@@ -62,6 +63,12 @@ state EXEC:
88
   command = string
89
       -> call cmd_exec($nosn, $command)
90
 
91
+# shmlog <size>|toggle|on|off
92
+state SHMLOG:
93
+  # argument may be a number
94
+  argument = string
95
+    -> call cmd_shmlog($argument)
96
+
97
 # border normal|none|1pixel|toggle|1pixel
98
 state BORDER:
99
   border_style = 'normal', 'pixel'

b/src/commands.c

104
@@ -13,6 +13,7 @@
105
 #include <stdarg.h>
106
 
107
 #include "all.h"
108
+#include "shmlog.h"
109
 
110
 // Macros to make the YAJL API a bit easier to use.
111
 #define y(x, ...) yajl_gen_ ## x (cmd_output->json_gen, ##__VA_ARGS__)
112
@@ -2027,3 +2028,28 @@ void cmd_bar(I3_CMD, char *bar_type, char *bar_value, char *bar_id) {
113
 
114
     update_barconfig();
115
 }
116
+
117
+/*
118
+ * Implementation of 'shmlog <size>|toggle|on|off'
119
+ *
120
+ */
121
+void cmd_shmlog(I3_CMD, char *argument) {
122
+    if (!strcmp(argument,"toggle"))
123
+        /* Toggle if default is not 0. If it is 0, set to default. */
124
+        shmlog_size = shmlog_size ? -shmlog_size : default_shmlog_size;
125
+    else if (!strcmp(argument, "off"))
126
+        shmlog_size = 0;
127
+    else if (!strcmp(argument, "on"))
128
+        shmlog_size = default_shmlog_size;
129
+    else {
130
+        /* Restart logging with the new size in the argument. */
131
+        shmlog_size = 0;
132
+        LOG("Restarting shm logging...\n");
133
+        init_logging();
134
+        shmlog_size = atoi(argument);
135
+    }
136
+    LOG("%s shm logging\n", shmlog_size > 0 ? "Enabling" : "Disabling");
137
+    init_logging();
138
+    update_shmlog_atom();
139
+    ysuccess(true);
140
+}

b/src/log.c

145
@@ -89,10 +89,21 @@ void init_logging(void) {
146
             }
147
         }
148
     }
149
+    /* Start SHM logging if shmlog_size is > 0. shmlog_size is SHMLOG_SIZE by
150
+     * default on development versions, and 0 on release versions. If it is
151
+     * not > 0, the user has turned it off, so let's close the logbuffer. */
152
+     if (shmlog_size > 0 && logbuffer == NULL)
153
+        open_logbuffer();
154
+     else if (shmlog_size <= 0 && logbuffer)
155
+        close_logbuffer();
156
+     atexit(purge_zerobyte_logfile);
157
+}
158
 
159
-    /* If this is a debug build (not a release version), we will enable SHM
160
-     * logging by default, unless the user turned it off explicitly. */
161
-    if (logbuffer == NULL && shmlog_size > 0) {
162
+/*
163
+ * Opens the logbuffer.
164
+ *
165
+ */
166
+void open_logbuffer(void) {
167
         /* Reserve 1% of the RAM for the logfile, but at max 25 MiB.
168
          * For 512 MiB of RAM this will lead to a 5 MiB log buffer.
169
          * At the moment (2011-12-10), no testcase leads to an i3 log
170
@@ -127,10 +138,8 @@ void init_logging(void) {
171
 
172
         logbuffer = mmap(NULL, logbuffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, logbuffer_shm, 0);
173
         if (logbuffer == MAP_FAILED) {
174
-            close(logbuffer_shm);
175
-            shm_unlink(shmlogname);
176
+            close_logbuffer();
177
             fprintf(stderr, "Could not mmap SHM segment for the i3 log: %s\n", strerror(errno));
178
-            logbuffer = NULL;
179
             return;
180
         }
181
 
182
@@ -148,8 +157,16 @@ void init_logging(void) {
183
         logwalk = logbuffer + sizeof(i3_shmlog_header);
184
         loglastwrap = logbuffer + logbuffer_size;
185
         store_log_markers();
186
-    }
187
-    atexit(purge_zerobyte_logfile);
188
+}
189
+
190
+/*
191
+ * Closes the logbuffer.
192
+ *
193
+ */
194
+void close_logbuffer(void) {
195
+    close(logbuffer_shm);
196
+    shm_unlink(shmlogname);
197
+    logbuffer = NULL;
198
 }
199
 
200
 /*

b/src/x.c

205
@@ -1064,6 +1064,16 @@ void x_set_name(Con *con, const char *name) {
206
 }
207
 
208
 /*
209
+ * Set up the I3_SHMLOG_PATH atom.
210
+ *
211
+ */
212
+void update_shmlog_atom() {
213
+    xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root,
214
+            A_I3_SHMLOG_PATH, A_UTF8_STRING, 8,
215
+            strlen(shmlogname), shmlogname);
216
+}
217
+
218
+/*
219
  * Sets up i3 specific atoms (I3_SOCKET_PATH and I3_CONFIG_PATH)
220
  *
221
  */
222
@@ -1075,8 +1085,7 @@ void x_set_i3_atoms(void) {
223
     xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A_I3_PID, XCB_ATOM_CARDINAL, 32, 1, &pid);
224
     xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A_I3_CONFIG_PATH, A_UTF8_STRING, 8,
225
                         strlen(current_configpath), current_configpath);
226
-    xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A_I3_SHMLOG_PATH, A_UTF8_STRING, 8,
227
-                        strlen(shmlogname), shmlogname);
228
+    update_shmlog_atom();
229
 }
230
 
231
 /*

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

236
@@ -144,7 +144,7 @@ is(parser_calls("\nworkspace test"),
237
 ################################################################################
238
 
239
 is(parser_calls('unknown_literal'),
240
-   "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" .
241
+   "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" .
242
    "ERROR: Your command: unknown_literal\n" .
243
    "ERROR:               ^^^^^^^^^^^^^^^",
244
    'error for unknown literal ok');