1/*
2 * Copyright 2003-2004, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * All rights reserved. Distributed under the terms of the MIT license.
4 */
5
6#include <errno.h>
7#include <fcntl.h>
8#include <stdarg.h>
9#include <stdio.h>
10#include <string.h>
11#include <unistd.h>
12
13#include <OS.h>
14
15#include "Debug.h"
16
17/*!
18	\file Debug.cpp
19	\brief Defines debug output function with printf() signature printing
20		   into a file.
21
22	\note The initialization is not thread safe!
23*/
24
25// locking support
26static int32 init_counter = 0;
27static sem_id dbg_printf_sem = -1;
28static thread_id dbg_printf_thread = -1;
29static int dbg_printf_nesting = 0;
30
31#if DEBUG_PRINT
32static int out = -1;
33#endif
34
35// init_debugging
36status_t
37init_debugging()
38{
39	status_t error = B_OK;
40	if (init_counter++ == 0) {
41		// open the file
42		#if DEBUG_PRINT
43			out = open(DEBUG_PRINT_FILE, O_RDWR | O_CREAT | O_TRUNC);
44			if (out < 0) {
45				error = errno;
46				init_counter--;
47			}
48		#endif	// DEBUG_PRINT
49		// allocate the semaphore
50		if (error == B_OK) {
51			dbg_printf_sem = create_sem(1, "dbg_printf");
52			if (dbg_printf_sem < 0)
53				error = dbg_printf_sem;
54		}
55		if (error == B_OK) {
56			#if DEBUG
57				__out("##################################################\n");
58			#endif
59		} else
60			exit_debugging();
61	}
62	return error;
63}
64
65// exit_debugging
66status_t
67exit_debugging()
68{
69	status_t error = B_OK;
70	if (--init_counter == 0) {
71		#if DEBUG_PRINT
72			close(out);
73			out = -1;
74		#endif	// DEBUG_PRINT
75		delete_sem(dbg_printf_sem);
76	} else
77		error = B_NO_INIT;
78	return error;
79}
80
81// dbg_printf_lock
82static inline
83bool
84dbg_printf_lock()
85{
86	thread_id thread = find_thread(NULL);
87	if (thread != dbg_printf_thread) {
88		if (acquire_sem(dbg_printf_sem) != B_OK)
89			return false;
90		dbg_printf_thread = thread;
91	}
92	dbg_printf_nesting++;
93	return true;
94}
95
96// dbg_printf_unlock
97static inline
98void
99dbg_printf_unlock()
100{
101	thread_id thread = find_thread(NULL);
102	if (thread != dbg_printf_thread)
103		return;
104	dbg_printf_nesting--;
105	if (dbg_printf_nesting == 0) {
106		dbg_printf_thread = -1;
107		release_sem(dbg_printf_sem);
108	}
109}
110
111// dbg_printf_begin
112void
113dbg_printf_begin()
114{
115	dbg_printf_lock();
116}
117
118// dbg_printf_end
119void
120dbg_printf_end()
121{
122	dbg_printf_unlock();
123}
124
125#if DEBUG_PRINT
126
127// dbg_printf
128void
129dbg_printf(const char *format,...)
130{
131	if (!dbg_printf_lock())
132		return;
133	char buffer[1024];
134	va_list args;
135	va_start(args, format);
136	// no vsnprintf() on PPC and in kernel
137	#if defined(__i386__) && USER
138		vsnprintf(buffer, sizeof(buffer) - 1, format, args);
139	#else
140		vsprintf(buffer, format, args);
141	#endif
142	va_end(args);
143	buffer[sizeof(buffer) - 1] = '\0';
144	write(out, buffer, strlen(buffer));
145	dbg_printf_unlock();
146}
147
148#endif	// DEBUG_PRINT
149