1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26
27 #include <klib/extern.h>
28 #include <klib/out.h>
29 #include <klib/status.h>
30 #include <klib/log.h>
31 #include <klib/debug.h>
32 #include <klib/text.h>
33 #include <klib/printf.h>
34 #include <klib/rc.h>
35 #include <klib/sort.h>
36 #include <sysalloc.h>
37 #include <atomic32.h>
38
39 #include "writer-priv.h"
40
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <ctype.h>
45 #include <os-native.h>
46 #include <assert.h>
47
48 #include <os-native.h>
49
50 static char wrt_app[32];
51 static size_t wrt_app_length;
52 static char wrt_vers[16];
53 static size_t wrt_vers_length;
54
55 void* KWrt_DefaultWriterDataStdOut = NULL;
56 void* KWrt_DefaultWriterDataStdErr = NULL;
57
58 typedef struct RCCreateLoc RCCreateLoc;
59 struct RCCreateLoc
60 {
61 const char *filename;
62 const char *function;
63 uint32_t lineno;
64 rc_t rc;
65 };
66
67 static RCCreateLoc RC_loc_queue [ 3 ];
68 static atomic32_t RC_loc_reserve, RC_loc_written, RC_loc_read;
69 #define RC_LOC_QUEUE_SIZE ( sizeof RC_loc_queue / sizeof RC_loc_queue [ 0 ] )
70 #define RC_LOC_QUEUE_MASK ( RC_LOC_QUEUE_SIZE - 1 )
71 static bool reporting_unread = false;
72
73 /*
74 * "appname" [ IN ] - identity of executable, usually argv[0]
75 *
76 * "vers" [ IN ] - 4-part version code: 0xMMmmrrrr, where
77 * MM = major release
78 * mm = minor release
79 * rrrr = bug-fix release
80 */
KWrtInit(const char * appname,uint32_t vers)81 LIB_EXPORT rc_t CC KWrtInit( const char* appname, uint32_t vers )
82 {
83 rc_t rc;
84
85 if ( appname == NULL )
86 return RC ( rcRuntime, rcLog, rcConstructing, rcString, rcNull );
87 if ( appname [ 0 ] == 0 )
88 return RC ( rcRuntime, rcLog, rcConstructing, rcString, rcEmpty );
89
90 do
91 {
92 const char* progname;
93 const char* ext;
94 size_t progname_z;
95
96 /* find whichever is last \ or / */
97 string_measure(appname, &progname_z);
98 progname = string_rchr(appname, progname_z, '/');
99 if( progname == NULL ) {
100 progname = appname;
101 } else {
102 progname++;
103 string_measure(progname, &progname_z);
104 }
105 appname = string_rchr(progname, progname_z, '\\');
106 if( appname == NULL ) {
107 appname = progname;
108 } else {
109 appname++;
110 }
111 string_measure(appname, &progname_z);
112
113 ext = string_chr(appname, progname_z, '.');
114
115 if( ext != NULL ) {
116 wrt_app_length = ext - appname;
117 } else {
118 wrt_app_length = progname_z;
119 }
120 if ( wrt_app_length >= sizeof(wrt_app) ) {
121 wrt_app_length = sizeof(wrt_app) - 1;
122 }
123 memmove(wrt_app, appname, wrt_app_length);
124 wrt_app[wrt_app_length] = '\0';
125
126 rc = string_printf ( wrt_vers, sizeof wrt_vers, & wrt_vers_length,
127 "%.3V", vers );
128 assert ( rc == 0 );
129
130 rc = KWrtSysInit(&KWrt_DefaultWriterDataStdOut, &KWrt_DefaultWriterDataStdErr);
131 if (rc) break;
132
133 rc = KOutInit();
134 if (rc) break;
135
136 rc = KLogInit();
137 if (rc) break;
138
139 rc = KStsInit();
140 if (rc) break;
141
142 rc = KDbgInit();
143 } while (0);
144
145 return rc;
146 }
147
simple_write(int fd,const void * buf,size_t count)148 LIB_EXPORT size_t CC simple_write( int fd, const void * buf, size_t count )
149 {
150 /* calls the platform-specific implementation ( $PLATFORM/syswriter.c ) */
151 return sys_simple_write( fd, buf, count );
152 }
153
is_a_tty(int fd)154 LIB_EXPORT int CC is_a_tty( int fd )
155 {
156 /* calls the platform-specific implementation ( $PLATFORM/syswriter.c ) */
157 return sys_is_a_tty( fd );
158 }
159
160 /*--------------------------------------------------------------------------
161 * nvp - name/value pair
162 */
163 static
wrt_nvp_cmp_func(const void * a,const void * b,void * ignored)164 int64_t CC wrt_nvp_cmp_func(const void *a, const void *b, void * ignored)
165 {
166 int i = 0;
167 const char *key = a;
168 const char *name = ( ( const wrt_nvp_t* ) b ) -> name;
169
170 while(key[i] == name[i]) {
171 if( key[i] == '\0' || name[i] == '\0' ) {
172 break;
173 }
174 ++i;
175 }
176 /* treat \0 or right-paren as key terminator */
177 if( key[i] != 0 && key[i] != ')' ) {
178 return (int64_t)key[i] - (int64_t)name[i];
179 }
180 return (int64_t)0 - (int64_t)name[i];
181 }
182
183 static
wrt_nvp_sort_func(const void * a,const void * b,void * ignored)184 int64_t CC wrt_nvp_sort_func(const void *a, const void *b, void * ignored)
185 {
186 const wrt_nvp_t *left = a;
187 const wrt_nvp_t *right = b;
188 return strcmp ( left -> name, right -> name );
189 }
190
wrt_nvp_sort(size_t argc,wrt_nvp_t argv[])191 LIB_EXPORT void CC wrt_nvp_sort( size_t argc, wrt_nvp_t argv[])
192 {
193 if( argc > 1 ) {
194 ksort(argv, argc, sizeof(argv[0]), wrt_nvp_sort_func, NULL);
195 }
196 }
197
wrt_nvp_find(size_t argc,const wrt_nvp_t argv[],const char * key)198 LIB_EXPORT const wrt_nvp_t* CC wrt_nvp_find( size_t argc, const wrt_nvp_t argv[], const char* key )
199 {
200 if( argc > 0 ) {
201 return kbsearch(key, argv, argc, sizeof(argv[0]), wrt_nvp_cmp_func, NULL);
202 }
203 return NULL;
204 }
205
wrt_nvp_find_value(size_t argc,const wrt_nvp_t argv[],const char * key)206 LIB_EXPORT const char* CC wrt_nvp_find_value( size_t argc, const wrt_nvp_t argv[], const char* key )
207 {
208 if( argc > 0 ) {
209 const wrt_nvp_t* n = (const wrt_nvp_t*)kbsearch(key, argv, argc, sizeof(argv[0]), wrt_nvp_cmp_func, NULL);
210 if( n != NULL ) {
211 return n->value;
212 }
213 }
214 return NULL;
215 }
216
217 static
RCLiteral(rc_t self,char * buffer,size_t bsize,size_t * num_writ)218 rc_t RCLiteral ( rc_t self, char *buffer, size_t bsize, size_t *num_writ )
219 {
220 #if ! _DEBUGGING && RECORD_RC_FILE_LINE
221 ( void ) GetRCLineno ();
222 #endif
223 return string_printf ( buffer, bsize, num_writ
224 #if _DEBUGGING
225 , "rc = %s:%u:$s:%u.%u.%u.%u.%u"
226 , GetRCFilename(), GetRCLineno (), GetRCFunction ()
227 #else
228 , "rc = %u.%u.%u.%u.%u"
229 #endif
230 , ( uint32_t ) GetRCModule ( self )
231 , ( uint32_t ) GetRCTarget ( self )
232 , ( uint32_t ) GetRCContext ( self )
233 , ( uint32_t ) GetRCObject ( self )
234 , ( uint32_t ) GetRCState ( self )
235 );
236 }
237
RCExplain(rc_t rc,char * buffer,size_t bsize,size_t * num_writ)238 LIB_EXPORT rc_t CC RCExplain ( rc_t rc, char *buffer, size_t bsize, size_t *num_writ )
239 {
240 return RCExplain2
241 ( rc, buffer, bsize, num_writ, eRCExOpt_CompleteMsg );
242 }
243
RCExplain2(rc_t rc,char * buffer,size_t bsize,size_t * num_writ,enum ERCExplain2Options options)244 LIB_EXPORT rc_t CC RCExplain2 ( rc_t rc, char *buffer, size_t bsize, size_t *num_writ,
245 enum ERCExplain2Options options )
246 {
247 bool noMessageIfNoError =
248 (options == eRCExOpt_NoMessageIfNoError ||
249 options == eRCExOpt_ObjAndStateOnlyIfError);
250 int len;
251 size_t total = 0;
252
253 const char *mod = GetRCModuleText ( GetRCModule ( rc ) );
254 const char *targ = GetRCTargetText ( GetRCTarget ( rc ) );
255 const char *ctx = GetRCContextText ( GetRCContext ( rc ) );
256 const char *obj = GetRCObjectText ( GetRCObject ( rc ) );
257 const char *state = GetRCStateText ( GetRCState ( rc ) );
258
259 assert( buffer && num_writ );
260
261 *num_writ = 0;
262 if( rc == 0 && noMessageIfNoError ) {
263 buffer[0] = '\0';
264 return 0;
265 }
266
267 /* English'ish formatting */
268 #if _DEBUGGING
269 {
270 const char *function = GetRCFunction ();
271 if ( function != NULL )
272 {
273 len = snprintf(buffer + total, bsize - total, "%s:%u:%s: ", GetRCFilename(), GetRCLineno (), function );
274 if( len < 0 || ( total + len ) >= bsize ) {
275 return RCLiteral ( rc, buffer, bsize, num_writ );
276 }
277 total += len;
278 }
279 }
280 #elif RECORD_RC_FILE_LINE
281 ( void ) GetRCLineno ();
282 #endif
283 if( obj != NULL ) {
284 len = snprintf(buffer + total, bsize - total, "%s", obj);
285 if( len < 0 || ( total + len ) >= bsize ) {
286 return RCLiteral ( rc, buffer, bsize, num_writ );
287 }
288 total += len;
289 }
290 if( state != NULL ) {
291 len = snprintf(buffer + total, bsize - total, "%s%s", total ? " " : "", state);
292 if( len < 0 || ( total + len ) >= bsize ) {
293 return RCLiteral ( rc, buffer, bsize, num_writ );
294 }
295 total += len;
296 }
297 if( rc != 0 && options == eRCExOpt_CompleteMsg ) {
298 if( ctx != NULL ) {
299 len = snprintf ( buffer + total, bsize - total, "%swhile %s", total ? " " : "", ctx );
300 if ( len < 0 || ( total + len ) >= bsize ) {
301 return RCLiteral ( rc, buffer, bsize, num_writ );
302 }
303 total += len;
304 if( targ != NULL ) {
305 len = snprintf ( buffer + total, bsize - total, "%s%s", total ? " " : "", targ );
306 if( len < 0 || ( total + len ) >= bsize ) {
307 return RCLiteral ( rc, buffer, bsize, num_writ );
308 }
309 total += len;
310 }
311 } else if( targ != NULL ) {
312 len = snprintf ( buffer + total,
313 bsize - total, "%swhile acting upon %s", total ? " " : "", targ );
314 if( len < 0 || ( total + len ) >= bsize ) {
315 return RCLiteral ( rc, buffer, bsize, num_writ );
316 }
317 total += len;
318 }
319 }
320 if( mod != NULL && options == eRCExOpt_CompleteMsg ) {
321 len = snprintf(buffer + total, bsize - total, "%swithin %s module", total ? " " : "", mod);
322 if( len < 0 || ( total + len ) >= bsize ) {
323 return RCLiteral ( rc, buffer, bsize, num_writ );
324 }
325 total += len;
326 }
327 *num_writ = total;
328 return 0;
329 }
330
331 /*--------------------------------------------------------------------------
332 * RC
333 */
334
335
336 /* GetRCModuleText
337 */
GetRCModuleText(enum RCModule mod)338 const char *GetRCModuleText ( enum RCModule mod )
339 {
340 if ( ( int ) mod < 0 || ( int ) mod >= ( int ) rcLastModule_v1_2 )
341 return "<INVALID-MODULE>";
342 return gRCModule_str [ ( int ) mod ];
343 }
344
345 /* GetRCModuleIdxText
346 */
GetRCModuleIdxText(enum RCModule mod)347 const char *GetRCModuleIdxText ( enum RCModule mod )
348 {
349 if ( ( int ) mod < 0 || ( int ) mod >= ( int ) rcLastModule_v1_2 )
350 return "<INVALID-MODULE>";
351 return gRCModuleIdx_str [ ( int ) mod ];
352 }
353
354 /* GetRCTargetText
355 */
GetRCTargetText(enum RCTarget targ)356 const char *GetRCTargetText ( enum RCTarget targ )
357 {
358 if ( ( int ) targ < 0 || ( int ) targ >= ( int ) rcLastTarget_v1_2 )
359 return "<INVALID-TARGET>";
360 return gRCTarget_str [ ( int ) targ ];
361 }
362
363 /* GetRCTargetIdxText
364 */
GetRCTargetIdxText(enum RCTarget targ)365 const char *GetRCTargetIdxText ( enum RCTarget targ )
366 {
367 if ( ( int ) targ < 0 || ( int ) targ >= ( int ) rcLastTarget_v1_2 )
368 return "<INVALID-TARGET>";
369 return gRCTargetIdx_str [ ( int ) targ ];
370 }
371
372 /* GetRCContextText
373 */
GetRCContextText(enum RCContext ctx)374 const char *GetRCContextText ( enum RCContext ctx )
375 {
376 if ( ( int ) ctx < 0 || ( int ) ctx >= ( int ) rcLastContext_v1_1 )
377 return "<INVALID-CONTEXT>";
378 return gRCContext_str [ ( int ) ctx ];
379 }
380
381 /* GetRCContextIdxText
382 */
GetRCContextIdxText(enum RCContext ctx)383 const char *GetRCContextIdxText ( enum RCContext ctx )
384 {
385 if ( ( int ) ctx < 0 || ( int ) ctx >= ( int ) rcLastContext_v1_1 )
386 return "<INVALID-CONTEXT>";
387 return gRCContextIdx_str [ ( int ) ctx ];
388 }
389
390 /* GetRCObjectText
391 */
GetRCObjectText(int obj)392 const char *GetRCObjectText ( int obj )
393 {
394 if ( ( int ) obj < 0 || ( int ) obj >= ( int ) rcLastObject_v1_2 )
395 return "<INVALID-OBJECT>";
396 if ( ( int ) obj < ( int ) rcLastTarget_v1_1 )
397 return gRCTarget_str [ ( int ) obj ];
398 return gRCObject_str [ ( int ) obj - ( int ) ( rcLastTarget_v1_1 - 1 ) ];
399 }
400
401 /* GetRCObjectIdxText
402 */
GetRCObjectIdxText(int obj)403 const char *GetRCObjectIdxText ( int obj )
404 {
405 if ( ( int ) obj < 0 || ( int ) obj >= ( int ) rcLastObject_v1_2 )
406 return "<INVALID-OBJECT>";
407 if ( ( int ) obj < ( int ) rcLastTarget_v1_1 )
408 return gRCTargetIdx_str [ ( int ) obj ];
409 return gRCObjectIdx_str [ ( int ) obj - ( int ) ( rcLastTarget_v1_1 - 1 ) ];
410 }
411
412 /* GetRCStateText
413 */
GetRCStateText(enum RCState state)414 const char *GetRCStateText ( enum RCState state )
415 {
416 if ( ( int ) state < 0 || ( int ) state >= ( int ) rcLastState_v1_1 )
417 return "<INVALID-STATE>";
418 return gRCState_str [ ( int ) state ];
419 }
420
421 /* GetRCStateIdxText
422 */
GetRCStateIdxText(enum RCState state)423 const char *GetRCStateIdxText ( enum RCState state )
424 {
425 if ( ( int ) state < 0 || ( int ) state >= ( int ) rcLastState_v1_1 )
426 return "<INVALID-STATE>";
427 return gRCStateIdx_str [ ( int ) state ];
428 }
429
430 static
read_rc_loc_head(void)431 uint32_t read_rc_loc_head ( void )
432 {
433 int32_t idx = atomic32_read ( & RC_loc_written );
434 if ( ! reporting_unread )
435 {
436 atomic32_set ( & RC_loc_read, idx );
437 }
438 return idx;
439 }
440
441 static
get_rc_filename(uint32_t idx)442 const char *get_rc_filename ( uint32_t idx )
443 {
444 const char *p = RC_loc_queue [ idx & RC_LOC_QUEUE_MASK ] . filename;
445 if( p != NULL )
446 {
447 int i;
448 const char *sep;
449 const char *RC_filename = p;
450 #if WINDOWS
451 static char win_rc_filename [ 4096 ];
452 size_t w, len = string_copy_measure ( win_rc_filename, sizeof win_rc_filename - 1, p );
453 if ( len >= 2 && isalpha ( win_rc_filename [ 0 ] ) && win_rc_filename [ 1 ] == ':' )
454 {
455 win_rc_filename [ 1 ] = win_rc_filename [ 0 ];
456 win_rc_filename [ 0 ] = '/';
457 }
458 for ( w = 0; w < len; ++ w )
459 {
460 if ( win_rc_filename [ w ] == '\\' )
461 win_rc_filename [ w ] = '/';
462 }
463 p = RC_filename = win_rc_filename;
464 #endif
465 if ( (p = strstr(RC_filename, "/interfaces/")) != NULL ||
466 (p = strstr(RC_filename, "/libs/")) != NULL ||
467 (p = strstr(RC_filename, "/services/")) != NULL ||
468 (p = strstr(RC_filename, "/tools/")) != NULL ||
469 (p = strstr(RC_filename, "/asm-trace/")) != NULL )
470 {
471 return p + 1;
472 }
473
474 for ( i = 0, sep = strrchr ( p = RC_filename, '/' ); sep != NULL && i < 3; ++ i )
475 {
476 p = sep + 1;
477 sep = string_rchr ( RC_filename, sep - RC_filename, '/' );
478 }
479 }
480
481 return p;
482 }
483
GetRCFilename(void)484 LIB_EXPORT const char * CC GetRCFilename ( void )
485 {
486 return get_rc_filename ( read_rc_loc_head () );
487 }
488
489 /* InsertSpace
490 * inserts a division after current text
491 *
492 * "spacer" [ IN, NULL OKAY ] - optional characters to insert
493 */
LogInsertSpace(const char * spacer,char * buffer,size_t bsize,size_t * num_writ)494 LIB_EXPORT rc_t CC LogInsertSpace(const char *spacer, char *buffer, size_t bsize, size_t *num_writ)
495 {
496 int len;
497
498 if ( spacer == NULL )
499 {
500 if ( bsize < 2 )
501 return RC ( rcRuntime, rcLog, rcLogging, rcBuffer, rcInsufficient );
502 buffer [ 0 ] = ' ';
503 buffer [ 1 ] = 0;
504 * num_writ = 1;
505 return 0;
506 }
507
508 len = snprintf ( buffer, bsize, "%s", spacer );
509
510 * num_writ = len;
511
512 if ( len < 0 || (size_t)len >= bsize )
513 {
514 if ( len < 0 )
515 * num_writ = 0;
516 return RC ( rcRuntime, rcLog, rcLogging, rcBuffer, rcInsufficient );
517 }
518
519 return 0;
520 }
521
LogAppName(char * buffer,size_t bsize,size_t * num_writ)522 LIB_EXPORT rc_t CC LogAppName(char *buffer, size_t bsize, size_t *num_writ)
523 {
524 if( wrt_app_length > bsize ) {
525 return RC(rcRuntime, rcLog, rcLogging, rcBuffer, rcInsufficient);
526 }
527 memmove(buffer, wrt_app, wrt_app_length);
528 *num_writ = wrt_app_length;
529 return 0;
530 }
531
LogAppVersion(char * buffer,size_t bsize,size_t * num_writ)532 LIB_EXPORT rc_t CC LogAppVersion(char *buffer, size_t bsize, size_t *num_writ)
533 {
534 if( wrt_vers_length > bsize ) {
535 return RC(rcRuntime, rcLog, rcLogging, rcBuffer, rcInsufficient);
536 }
537 memmove(buffer, wrt_vers, wrt_vers_length);
538 *num_writ = wrt_vers_length;
539 return 0;
540 }
541
LogFlush(const KWrtHandler * handler,const char * buffer,const size_t bsize)542 LIB_EXPORT rc_t CC LogFlush ( const KWrtHandler* handler, const char *buffer, const size_t bsize)
543 {
544 rc_t rc = 0;
545 size_t num_written;
546 size_t remaining;
547
548 assert(handler != NULL);
549 assert(buffer != NULL);
550
551 for(remaining = bsize; rc == 0 && remaining > 0; remaining -= num_written, buffer += num_written) {
552 rc = handler->writer(handler->data, buffer, remaining, &num_written);
553 }
554 return rc;
555 }
556
557 static
get_rc_function(uint32_t idx)558 const char *get_rc_function ( uint32_t idx )
559 {
560 return RC_loc_queue [ idx & RC_LOC_QUEUE_MASK ] . function;
561 }
562
GetRCFunction(void)563 LIB_EXPORT const char * CC GetRCFunction ( void )
564 {
565 return get_rc_function ( read_rc_loc_head () );
566 }
567
568 static
get_rc_lineno(uint32_t idx)569 uint32_t get_rc_lineno ( uint32_t idx )
570 {
571 return RC_loc_queue [ idx & RC_LOC_QUEUE_MASK ] . lineno;
572 }
573
GetRCLineno(void)574 LIB_EXPORT uint32_t CC GetRCLineno ( void )
575 {
576 return get_rc_lineno ( read_rc_loc_head () );
577 }
578
579 static
get_rc_code(uint32_t idx)580 rc_t get_rc_code ( uint32_t idx )
581 {
582 return RC_loc_queue [ idx & RC_LOC_QUEUE_MASK ] . rc;
583 }
584
SetRCFileFuncLine(rc_t rc,const char * filename,const char * funcname,uint32_t lineno)585 LIB_EXPORT rc_t CC SetRCFileFuncLine ( rc_t rc, const char *filename, const char *funcname, uint32_t lineno )
586 {
587 /* the limit based upon last guy successfully written */
588 int32_t lim = atomic32_read ( & RC_loc_written ) + RC_LOC_QUEUE_SIZE;
589
590 /* try to reserve a slot for writing */
591 int32_t rsrv = atomic32_read_and_add_lt ( & RC_loc_reserve, 1, lim ) + 1;
592
593 /* see if we got the reservation */
594 if ( rsrv <= lim )
595 {
596 uint32_t idx = rsrv & RC_LOC_QUEUE_MASK;
597 RC_loc_queue [ idx ] . filename = filename;
598 RC_loc_queue [ idx ] . function = funcname;
599 RC_loc_queue [ idx ] . lineno = lineno;
600 RC_loc_queue [ idx ] . rc = rc;
601 /* TBD - proper release sequence */
602 atomic32_set ( & RC_loc_written, rsrv );
603 }
604
605 return rc;
606 }
607
608 /* GetUnreadRCInfo
609 * expected to be called after all threads are quiet
610 */
GetUnreadRCInfo(rc_t * rc,const char ** filename,const char ** funcname,uint32_t * lineno)611 LIB_EXPORT bool CC GetUnreadRCInfo ( rc_t *rc, const char **filename, const char **funcname, uint32_t *lineno )
612 {
613 int32_t last_writ;
614
615 reporting_unread = true;
616
617 /* these are not atomic, but the ordering is important */
618 last_writ = atomic32_read ( & RC_loc_written );
619 if ( last_writ > 0 )
620 {
621 /* this arrangement attempts to make the access to
622 RC_loc_read dependent upon access to RC_loc_written */
623 int32_t last_read = atomic32_read ( & RC_loc_read );
624 if ( last_read < last_writ )
625 {
626 /* check reserved slots */
627 int32_t rsrv = atomic32_read ( & RC_loc_reserve );
628
629 /* adjust last read */
630 if ( last_writ - last_read > RC_LOC_QUEUE_SIZE )
631 last_read = last_writ - RC_LOC_QUEUE_SIZE;
632
633 /* any reserved rows must be considered overwritten */
634 last_read += rsrv - last_writ;
635
636 /* these are the rows we can report */
637 if ( last_read < last_writ )
638 {
639 int32_t idx = last_read + 1;
640 atomic32_set ( & RC_loc_read, idx );
641
642 if ( filename != NULL )
643 * filename = get_rc_filename ( idx );
644 if ( funcname != NULL )
645 * funcname = get_rc_function ( idx );
646 if ( lineno != NULL )
647 * lineno = get_rc_lineno ( idx );
648 if ( rc != NULL )
649 * rc = get_rc_code ( idx );
650
651 return true;
652 }
653 }
654 }
655 reporting_unread = false;
656 return false;
657 }
658