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'); |