1 /* hiiosdump.c - Hiquu I/O Engine data structure dump 2 * Copyright (c) 2006,2012 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved. 3 * This is confidential unpublished proprietary source code of the author. 4 * NO WARRANTY, not even implied warranties. Contains trade secrets. 5 * Distribution prohibited unless authorized in writing. See file COPYING. 6 * Special grant: hiios.c may be used with zxid open source project under 7 * same licensing terms as zxid itself. 8 * $Id$ 9 * 10 * 15.4.2006, created over Easter holiday --Sampo 11 * 16.8.2012, modified license grant to allow use with ZXID.org --Sampo 12 * 13 * See http://pl.atyp.us/content/tech/servers.html for inspiration on threading strategy. 14 * 15 * MANY ELEMENTS IN QUEUE ONE ELEMENT IN Q EMPTY QUEUE 16 * consume produce consume produce consume produce 17 * | | | ,-------' | | 18 * v v v v v v 19 * qel.n --> qel.n --> qel.n --> 0 qel.n --> 0 0 0 20 */ 21 22 #include "platform.h" 23 24 #include <pthread.h> 25 #include <memory.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <unistd.h> 29 #include <errno.h> 30 #include <string.h> 31 32 #include "akbox.h" 33 #include "hiproto.h" 34 #include "hiios.h" 35 #include "errmac.h" 36 37 /* Current color for coloring data structures for integrity checking, e.g. 38 * gdb p hi_color+=4, hi_sanity_hit(255, hit) 39 * Note that different color MUST be used for each analysis and some 40 * analysis iterations involve several classes of next pointers. This 41 * is solved by having different classes being represented by color plus 42 * offset. However, this means that color must be incremented in steps of 4. 43 * hi_color+0 qel.n -- free_pdus, todo_consume 44 * hi_color+1 pdu->n, io->n -- reqs 45 * hi_color+2 pdu->wn -- to_write 46 * The color takes space as a struct field, thus only 8 or 16 bits are 47 * supplied (varies over time with implementation), which should 48 * allow most debugging chores, but may not be adequate for some. */ 49 short hi_color = 4; 50 51 /*() Sanity check hiios pdu data structures. 52 * Returns number of nodes scanned, or negative for errors. */ 53 54 /* Called by: hi_sanity_hit, hi_sanity_io x4, hi_sanity_pdu x3, hi_sanity_shf x2 */ 55 int hi_sanity_pdu(int mode, struct hi_pdu* root_pdu) 56 { 57 int errs = 0; 58 int nodes = 0; 59 struct hi_pdu* pdu; 60 61 if (mode&0x80) { 62 if (root_pdu->reals) 63 printf(" pdu_%p //reals (%.*s)\n", root_pdu, (int)MIN(root_pdu->ap-root_pdu->m,4), root_pdu->m); 64 else 65 printf(" pdu_%p -> null [label=reals];\n", root_pdu); 66 } 67 for (pdu = root_pdu->reals; pdu; pdu = pdu->n) { 68 if (mode&0x80) printf(" -> pdu_%p // (%.*s)\n", pdu, (int)MIN(pdu->ap-pdu->m,4), pdu->m); 69 if (pdu->color == hi_color+1) { 70 printf("ERR *** pdu_%p has circular reference (color=%d) wrt pdu->reals pdu->n\n", pdu, pdu->color); 71 --errs; 72 break; 73 } else { 74 pdu->color = hi_color+1; 75 ++nodes; 76 if (mode&0x01) nodes += hi_sanity_pdu(mode, pdu); 77 } 78 if (pdu->qel.intodo != HI_INTODO_PDUINUSE) { 79 printf("ERR *** pdu_%p has wrong intodo=%x expected %x\n", pdu, pdu->qel.intodo, HI_INTODO_PDUINUSE); 80 --errs; 81 } 82 } 83 if (mode&0x80 && root_pdu->reals) printf(" [label=reals];\n"); 84 85 if (mode&0x80) { 86 if (root_pdu->synths) 87 printf(" pdu_%p // synths\n", root_pdu); 88 else 89 printf(" pdu_%p -> null [label=synths];\n", root_pdu); 90 } 91 for (pdu = root_pdu->synths; pdu; pdu = pdu->n) { 92 if (mode&0x80) printf(" -> pdu_%p\n", pdu); 93 if (pdu->color == hi_color+1) { 94 printf("ERR *** pdu_%p has circular reference (color=%d) wrt pdu->synths pdu->n\n", pdu, pdu->color); 95 --errs; 96 break; 97 } else { 98 pdu->color = hi_color+1; 99 ++nodes; 100 if (mode&0x01) nodes += hi_sanity_pdu(mode, pdu); 101 } 102 if (pdu->qel.intodo != HI_INTODO_PDUINUSE) { 103 printf("ERR *** pdu_%p has wrong intodo=%x expected %x\n", pdu, pdu->qel.intodo, HI_INTODO_PDUINUSE); 104 --errs; 105 } 106 } 107 if (mode&0x80 && root_pdu->synths) printf(" [label=synths];\n"); 108 109 if (mode&0x80) { 110 if (root_pdu->subresps) 111 printf(" pdu_%p // subresps\n", root_pdu); 112 else 113 printf(" pdu_%p -> null [label=subresps];\n", root_pdu); 114 } 115 for (pdu = root_pdu->subresps; pdu; pdu = pdu->wn) { 116 if (mode&0x80) printf(" -> pdu_%p\n", pdu); 117 if (pdu->color == hi_color+2) { 118 printf("ERR *** pdu_%p has circular reference (color=%d) wrt pdu->subresps pdu->wn\n", pdu, pdu->color); 119 --errs; 120 break; 121 } else { 122 pdu->color = hi_color+2; 123 ++nodes; 124 if (mode&0x01) nodes += hi_sanity_pdu(mode, pdu); 125 } 126 if (pdu->qel.intodo != HI_INTODO_PDUINUSE) { 127 printf("ERR *** pdu_%p has wrong intodo=%x expected %x\n", pdu, pdu->qel.intodo, HI_INTODO_PDUINUSE); 128 --errs; 129 } 130 } 131 if (mode&0x80 && root_pdu->subresps) printf(" [label=subresps];\n"); 132 133 return errs?errs:nodes; 134 } 135 136 /*() Sanity check hiios io data structures. 137 * Returns number of nodes scanned, or negative for errors. */ 138 139 /* Called by: hi_sanity_shf */ 140 int hi_sanity_io(int mode, struct hi_io* root_io) 141 { 142 int errs = 0; 143 int nodes = 0; 144 struct hi_pdu* pdu; 145 146 if (root_io->fd & 0x80000000 || root_io->fd == 0) { 147 if (mode&0x80) printf("io_%p [label=nc]; // fd=0x%x\n", root_io, root_io->fd); 148 return 0; 149 } 150 151 if (mode&0x80) printf(" io_%p -> pdu_%p [label=cur_pdu]; // fd=0x%x\n", root_io, root_io->cur_pdu, root_io->fd); 152 if (root_io->cur_pdu) 153 root_io->cur_pdu->color = hi_color+1; /* cur_pdu is mutually exclusive with io->reqs */ 154 155 if (mode&0x80) { 156 if (root_io->reqs) 157 printf(" io_%p // reqs\n", root_io); 158 else 159 printf(" io_%p -> null [label=reqs];\n", root_io); 160 } 161 for (pdu = root_io->reqs; pdu; pdu = pdu->n) { 162 if (mode&0x80) printf(" -> pdu_%p // (%.*s)\n", pdu, (int)MIN(pdu->ap-pdu->m,4), pdu->m); 163 if (pdu->color == hi_color+1) { 164 printf("ERR *** pdu_%p has circular reference (color=%d) wrt io->reqs pdu->n\n", pdu, pdu->color); 165 --errs; 166 break; 167 } else { 168 pdu->color = hi_color+1; 169 ++nodes; 170 if (mode&0x02) nodes += hi_sanity_pdu(mode, pdu); 171 } 172 if (pdu->qel.intodo != HI_INTODO_PDUINUSE) { 173 printf("ERR *** pdu_%p has wrong intodo=%x expected %x\n", pdu, pdu->qel.intodo, HI_INTODO_PDUINUSE); 174 --errs; 175 } 176 } 177 if (mode&0x80 && root_io->reqs) printf("[label=reqs];\n"); 178 179 if (mode&0x80) { 180 if (root_io->pending) 181 printf(" io_%p // pending\n", root_io); 182 else 183 printf(" io_%p -> null [label=pending];\n", root_io); 184 } 185 for (pdu = root_io->pending; pdu; pdu = pdu->n) { 186 if (mode&0x80) printf(" -> pdu_%p // (%.*s)\n", pdu, (int)MIN(pdu->ap-pdu->m,4), pdu->m); 187 if (pdu->color == hi_color+1) { 188 printf("ERR *** pdu_%p has circular reference (color=%d) wrt io->pending pdu->n\n", pdu, pdu->color); 189 --errs; 190 break; 191 } else { 192 pdu->color = hi_color+1; 193 ++nodes; 194 if (mode&0x02) nodes += hi_sanity_pdu(mode, pdu); 195 } 196 if (pdu->qel.intodo != HI_INTODO_PDUINUSE) { 197 printf("ERR *** pdu_%p has wrong intodo=%x expected %x\n", pdu, pdu->qel.intodo, HI_INTODO_PDUINUSE); 198 --errs; 199 } 200 } 201 if (mode&0x80 && root_io->reqs) printf("[label=pending];\n"); 202 203 if (mode&0x80) { 204 if (root_io->to_write_produce) { 205 printf(" io_%p -> pdu_%p [label=to_write_produce]; // (%.*s)\n", root_io, root_io->to_write_produce, (int)MIN(root_io->to_write_produce->ap-root_io->to_write_produce->m,4), root_io->to_write_produce->m); 206 ASSERT(root_io->to_write_produce->wn == 0); 207 /*if (mode&0x02) nodes += hi_sanity_pdu(mode, root_io->to_write_produce);*/ 208 if (pdu->qel.intodo != HI_INTODO_PDUINUSE) { 209 printf("ERR *** pdu_%p has wrong intodo=%x expected %x\n", pdu, pdu->qel.intodo, HI_INTODO_PDUINUSE); 210 --errs; 211 } 212 } else 213 printf(" io_%p -> null [label=to_write_produce];\n", root_io); 214 } 215 216 if (mode&0x80) { 217 if (root_io->to_write_consume) 218 printf(" io_%p // to_write_consume\n", root_io); 219 else 220 printf(" io_%p -> null [label=to_write_consume]; // n_to_write=%d\n", root_io, root_io->n_to_write); 221 } 222 for (pdu = root_io->to_write_consume; pdu; pdu = pdu->wn) { 223 if (mode&0x80) printf(" -> pdu_%p // (%.*s)\n", pdu, (int)MIN(pdu->ap-pdu->m,4), pdu->m); 224 if (pdu->color == hi_color+2) { 225 printf("ERR *** pdu_%p has circular reference (color=%d) wrt io->to_write_consume pdu->wn\n", pdu, pdu->color); 226 --errs; 227 break; 228 } else { 229 pdu->color = hi_color+2; 230 ++nodes; 231 if (mode&0x02) nodes += hi_sanity_pdu(mode, pdu); 232 } 233 if (pdu->qel.intodo != HI_INTODO_PDUINUSE) { 234 printf("ERR *** pdu_%p has wrong intodo=%x expected %x\n", pdu, pdu->qel.intodo, HI_INTODO_PDUINUSE); 235 --errs; 236 } 237 } 238 if (mode&0x80 && root_io->to_write_consume) printf("[label=to_write_consume]; // n_to_write=%d\n", root_io->n_to_write); 239 240 if (mode&0x80) { 241 if (root_io->in_write) 242 printf("io_%p // in_write\n", root_io); 243 else 244 printf(" io_%p -> null [label=in_write];\n", root_io); 245 } 246 for (pdu = root_io->in_write; pdu; pdu = pdu->wn) { 247 if (mode&0x80) printf("-> pdu_%p // (%.*s)\n", pdu, (int)MIN(pdu->ap-pdu->m,4), pdu->m); 248 if (pdu->color == hi_color+2) { 249 printf("ERR *** pdu_%p has circular reference (color=%d) wrt io->in_write pdu->wn\n", pdu, pdu->color); 250 --errs; 251 break; 252 } else { 253 pdu->color = hi_color+2; 254 ++nodes; 255 if (mode&0x02) nodes += hi_sanity_pdu(mode, pdu); 256 } 257 if (pdu->qel.intodo != HI_INTODO_PDUINUSE) { 258 printf("ERR *** pdu_%p has wrong intodo=%x expected %x\n", pdu, pdu->qel.intodo, HI_INTODO_PDUINUSE); 259 --errs; 260 } 261 } 262 if (mode&0x80 && root_io->in_write) printf("[label=in_write];\n"); 263 264 return errs?errs:nodes; 265 } 266 267 /*() Sanity check hiios thread data structures. 268 * Returns number of nodes scanned, or negative for errors. */ 269 270 /* Called by: hi_dump, hi_sanity */ 271 int hi_sanity_hit(int mode, struct hi_thr* root_hit) 272 { 273 int errs = 0; 274 int nodes = 0; 275 struct hi_pdu* pdu; 276 277 printf("hit_%p [label=\"tid_%x\"];\n", root_hit, (unsigned int)root_hit->self); 278 if (mode&0x80) { 279 if (root_hit->free_pdus) 280 printf("hit_%p // free_pdus\n", root_hit); 281 else 282 printf("hit_%p -> null [label=free_pdus];\n", root_hit); 283 } 284 for (pdu = root_hit->free_pdus; pdu; pdu = (struct hi_pdu*)pdu->qel.n) { 285 if (mode&0x80) printf("-> pdu_%p // (%.*s)\n", pdu, (int)MIN(pdu->ap-pdu->m,4), pdu->m); 286 if (pdu->color == hi_color+1) { 287 printf("ERR *** pdu_%p in hit->free_pdus is also in reqs list (color=%d)\n", pdu, pdu->color); 288 --errs; 289 break; 290 } 291 if (pdu->color == hi_color+0) { 292 printf("ERR *** pdu_%p has circular reference (color=%d) wrt hit->free_pdus pdu->qel.n\n", pdu, pdu->color); 293 --errs; 294 break; 295 } 296 if (pdu->qel.intodo != HI_INTODO_HIT_FREE) { 297 printf("ERR *** pdu_%p has wrong intodo=%x expected %x\n", pdu, pdu->qel.intodo, HI_INTODO_HIT_FREE); 298 --errs; 299 } 300 pdu->color = hi_color+0; 301 ++nodes; 302 if (!(mode&0x08)) nodes += hi_sanity_pdu(mode, pdu); 303 } 304 if (mode&0x80 && root_hit->free_pdus) printf("[label=free_pdus];\n"); 305 306 return errs?errs:nodes; 307 } 308 309 /*() Sanity check hiios shuffler data structures, i.e. practically everything. 310 * Mainly meant to be called from gdb like this: p hi_color+=4, hi_sanity(255, shf) 311 * The mode argument controls recursion and output of a visualization 312 * of the data structure. It consists of bits as follows 313 * 76543210 314 * | |||`-- recurse on sub PDU (0x01) 315 * | ||`--- recurse on PDU (0x02) 316 * | |`---- recurse on IO (0x04) 317 * | `----- do not recurse on free_pdu (0x08) 318 * `--------- print (0x80) 319 * Simple way to enable all recusion is to use mode=127 or mode=255 if print is desired 320 * Returns negative number (of errors) if errors are found. Otherwise positive 321 * number representing the rough number of nodes traversed (size of the data structure) 322 * is returned. 323 * hi_sanity() will most probably crash upon corrupt pointers. It will make 324 * an attempt to detect illegal circular data structures (see hi_color). 325 * (gdb) p hi_color+=4, hi_sanity(255, shuff) 326 */ 327 328 /* Called by: hi_dump, hi_sanity, hi_shuffle, zxbusd_main */ 329 int hi_sanity_shf(int mode, struct hiios* root_shf) 330 { 331 int res; 332 int errs = 0; 333 int nodes = 0; 334 struct hi_qel* qe; 335 struct hi_pdu* pdu; 336 struct hi_io* io; 337 338 if (mode&0x80) { 339 if (root_shf->ios) 340 printf("shf_%p // max_ios=%d\n", root_shf, root_shf->max_ios); 341 else 342 printf("shf_%p -> null [label=ios];\n", root_shf); 343 } 344 for (io = root_shf->ios; io < root_shf->ios + root_shf->max_ios; ++io) { 345 if (!io->n_thr && (io->fd & 0x80000000 || io->fd == 0)) { 346 /*ASSERT(io->qel.intodo == HI_INTODO_SHF_FREE); doesn't hold betw 1st close and end game */ 347 printf("io_%p // free? fd(%x) n_c/t=%d/%d in_todo=%d\n", io, io->fd, io->n_close, io->n_thr, io->qel.intodo); 348 continue; /* ios slot not in use */ 349 } 350 if (mode&0x80) printf("-> io_%p\n", io); 351 ++nodes; 352 if (mode&0x04) { 353 res = hi_sanity_io(mode, io); 354 if (res < 0) 355 errs += res; 356 else 357 nodes += res; 358 } 359 } 360 if (mode&0x80 && root_shf->ios) printf("[label=ios];\n"); 361 362 if (mode&0x80) { 363 if (root_shf->todo_consume) 364 printf("shf_%p // todo_consume (color=%d)\n", root_shf, hi_color+0); 365 else 366 printf("shf_%p -> null [label=todo_consume];\n", root_shf); 367 } 368 for (qe = root_shf->todo_consume; qe; qe = qe->n) { 369 if (mode&0x80) printf("-> qe_%p\n", qe); 370 #if 0 371 if (pdu->color == hi_color+0) { 372 printf("ERR *** pdu_%p has circular reference (color=%d) wrt hit->free_pdus pdu->qel.n\n", pdu, pdu->color); 373 --errs; 374 break; 375 } 376 pdu->color = hi_color+0; 377 ++nodes; 378 if (!(mode&0x08)) { 379 res = hi_sanity_pdu(mode, pdu); 380 if (res < 0) 381 errs += res; 382 else 383 nodes += res; 384 } 385 #endif 386 if (qe->intodo != HI_INTODO_INTODO) { 387 printf("ERR *** qe_%p has wrong intodo=%x expected %x\n", qe, qe->intodo, HI_INTODO_INTODO); 388 --errs; 389 } 390 } 391 if (mode&0x80 && root_shf->todo_consume) printf("[label=todo_consume];\n"); 392 393 if (mode&0x80) { 394 if (root_shf->free_pdus) 395 printf("shf_%p // free_pdus (color=%d)\n", root_shf, hi_color+0); 396 else 397 printf("shf_%p -> null [label=free_pdus];\n", root_shf); 398 } 399 for (pdu = root_shf->free_pdus; pdu; pdu = (struct hi_pdu*)pdu->qel.n) { 400 if (mode&0x80) printf("-> pdu_%p ", pdu); 401 if (pdu->color == hi_color+1) { 402 printf("ERR *** pdu_%p in free list is also in reqs list (color=%d)\n", pdu, pdu->color); 403 --errs; 404 break; 405 } 406 if (pdu->color == hi_color+0) { 407 printf("ERR *** pdu_%p has circular reference (color=%d) wrt hit->free_pdus pdu->qel.n\n", pdu, pdu->color); 408 --errs; 409 break; 410 } 411 if (pdu->qel.intodo != HI_INTODO_SHF_FREE) { 412 printf("ERR *** pdu_%p has wrong intodo=%x expected %x\n", pdu, pdu->qel.intodo, HI_INTODO_SHF_FREE); 413 --errs; 414 } 415 pdu->color = hi_color+0; 416 ++nodes; 417 if (!(mode&0x08)) { 418 res = hi_sanity_pdu(mode, pdu); 419 if (res < 0) 420 errs += res; 421 else 422 nodes += res; 423 } 424 } 425 if (mode&0x80 && root_shf->free_pdus) printf("[label=free_pdus];\n"); 426 427 return errs?errs:nodes; 428 } 429 430 /*() hi_sanity is called by macro HI_SANITY() and is meant to be called from gdb interactively. 431 * Returns number of nodes scanned, or negative for errors. */ 432 433 /* Called by: */ 434 int hi_sanity(int mode, struct hiios* root_shf, struct hi_thr* root_hit, const char* fn, int line) 435 { 436 int res; 437 hi_color += 4; 438 if (root_shf) { 439 res = hi_sanity_shf(mode, root_shf); 440 D("Data structure dump %d\n---------------------- %s:%d", res, fn, line); 441 ASSERT(res >= 0); 442 } 443 if (root_hit) { 444 res = hi_sanity_hit(mode, root_hit); 445 D("Hit structure dump %d\n====================== %s:%d", res, fn, line); 446 ASSERT(res >= 0); 447 } 448 return 0; 449 } 450 451 /*() All thread data structure check. 452 * Returns number of nodes scanned, or negative for errors. */ 453 454 /* Called by: */ 455 int hi_dump(struct hiios* shf) 456 { 457 struct hi_thr* hit; 458 int res = hi_sanity_shf(255, shf); 459 hi_color += 4; 460 D("Dumping shf=%p hi_color=%d", shf, hi_color); 461 printf("Data structure dump %d\n----------------------\n", res); 462 for (hit = shf->threads; hit; hit = hit->n) { 463 res = hi_sanity_hit(255, hit); 464 printf("Hit structure dump %d\n======================\n", res); 465 } 466 return res; 467 } 468 469 /* EOF -- hiiosdump.c */ 470