xref: /haiku/src/apps/debugger/user_interface/report/ReportUserInterface.cpp (revision 46b7da1f4f40f7157d74fc7fb26ff9ec7f2416f2)
1 /*
2  * Copyright 2015-2016, Rene Gollent, rene@gollent.com.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "ReportUserInterface.h"
8 
9 #include <stdio.h>
10 
11 #include <Entry.h>
12 #include <FindDirectory.h>
13 #include <Path.h>
14 
15 #include <AutoLocker.h>
16 
17 #include "MessageCodes.h"
18 #include "UiUtils.h"
19 
20 
ReportUserInterface(thread_id targetThread,const char * reportPath)21 ReportUserInterface::ReportUserInterface(thread_id targetThread,
22 	const char* reportPath)
23 	:
24 	fTeam(NULL),
25 	fListener(NULL),
26 	fTargetThread(targetThread),
27 	fReportPath(reportPath),
28 	fShowSemaphore(-1),
29 	fReportSemaphore(-1),
30 	fShown(false),
31 	fTerminating(false)
32 {
33 }
34 
35 
~ReportUserInterface()36 ReportUserInterface::~ReportUserInterface()
37 {
38 	if (fShowSemaphore >= 0)
39 		delete_sem(fShowSemaphore);
40 
41 	if (fTeam != NULL)
42 		fTeam->RemoveListener(this);
43 }
44 
45 
46 const char*
ID() const47 ReportUserInterface::ID() const
48 {
49 	return "ReportUserInterface";
50 }
51 
52 
53 status_t
Init(Team * team,UserInterfaceListener * listener)54 ReportUserInterface::Init(Team* team, UserInterfaceListener* listener)
55 {
56 	fShowSemaphore = create_sem(0, "show report");
57 	if (fShowSemaphore < 0)
58 		return fShowSemaphore;
59 
60 	fReportSemaphore = create_sem(0, "report generator wait");
61 	if (fReportSemaphore < 0)
62 		return fReportSemaphore;
63 
64 	fTeam = team;
65 	fListener = listener;
66 
67 	fTeam->AddListener(this);
68 
69 	return B_OK;
70 }
71 
72 
73 void
Show()74 ReportUserInterface::Show()
75 {
76 	fShown = true;
77 	release_sem(fShowSemaphore);
78 }
79 
80 
81 void
Terminate()82 ReportUserInterface::Terminate()
83 {
84 	fTerminating = true;
85 }
86 
87 
88 UserInterface*
Clone() const89 ReportUserInterface::Clone() const
90 {
91 	// the report interface does not support cloning, since
92 	// it won't ever be asked to interactively restart.
93 	return NULL;
94 }
95 
96 
97 bool
IsInteractive() const98 ReportUserInterface::IsInteractive() const
99 {
100 	return false;
101 }
102 
103 
104 status_t
LoadSettings(const TeamUiSettings * settings)105 ReportUserInterface::LoadSettings(const TeamUiSettings* settings)
106 {
107 	return B_OK;
108 }
109 
110 
111 status_t
SaveSettings(TeamUiSettings * & settings) const112 ReportUserInterface::SaveSettings(TeamUiSettings*& settings) const
113 {
114 	return B_OK;
115 }
116 
117 
118 void
NotifyUser(const char * title,const char * message,user_notification_type type)119 ReportUserInterface::NotifyUser(const char* title, const char* message,
120 	user_notification_type type)
121 {
122 }
123 
124 
125 void
NotifyBackgroundWorkStatus(const char * message)126 ReportUserInterface::NotifyBackgroundWorkStatus(const char* message)
127 {
128 }
129 
130 
131 int32
SynchronouslyAskUser(const char * title,const char * message,const char * choice1,const char * choice2,const char * choice3)132 ReportUserInterface::SynchronouslyAskUser(const char* title,
133 	const char* message, const char* choice1, const char* choice2,
134 	const char* choice3)
135 {
136 	return -1;
137 }
138 
139 
140 status_t
SynchronouslyAskUserForFile(entry_ref * _ref)141 ReportUserInterface::SynchronouslyAskUserForFile(entry_ref* _ref)
142 {
143 	return B_UNSUPPORTED;
144 }
145 
146 
147 void
Run()148 ReportUserInterface::Run()
149 {
150 	// Wait for the Show() semaphore to be released.
151 	status_t error;
152 	do {
153 		error = acquire_sem(fShowSemaphore);
154 	} while (error == B_INTERRUPTED);
155 
156 	if (error != B_OK)
157 		return;
158 
159 	bool waitNeeded = false;
160 	if (fTargetThread > 0) {
161 		AutoLocker< ::Team> teamLocker(fTeam);
162 		::Thread* thread = fTeam->ThreadByID(fTargetThread);
163 		if (thread == NULL)
164 			waitNeeded = true;
165 		else if (thread->State() != THREAD_STATE_STOPPED) {
166 			waitNeeded = true;
167 			fListener->ThreadActionRequested(fTargetThread, MSG_THREAD_STOP);
168 		}
169 	}
170 
171 	if (waitNeeded) {
172 		do {
173 			error = acquire_sem(fShowSemaphore);
174 		} while (error == B_INTERRUPTED);
175 
176 		if (error != B_OK)
177 			return;
178 	}
179 
180 	entry_ref ref;
181 	if (fReportPath != NULL && fReportPath[0] == '/') {
182 		error = get_ref_for_path(fReportPath, &ref);
183 	} else {
184 		char filename[B_FILE_NAME_LENGTH];
185 		if (fReportPath != NULL)
186 			strlcpy(filename, fReportPath, sizeof(filename));
187 		else
188 			UiUtils::ReportNameForTeam(fTeam, filename, sizeof(filename));
189 
190 		BPath path;
191 		error = find_directory(B_DESKTOP_DIRECTORY, &path);
192 		if (error == B_OK)
193 			error = path.Append(filename);
194 		if (error == B_OK)
195 			error = get_ref_for_path(path.Path(), &ref);
196 	}
197 
198 	if (error != B_OK)
199 		printf("Unable to get ref for report path %s\n", strerror(error));
200 	else {
201 		fListener->DebugReportRequested(&ref);
202 
203 		do {
204 			error = acquire_sem(fReportSemaphore);
205 		} while (error == B_INTERRUPTED);
206 	}
207 
208 	fListener->UserInterfaceQuitRequested(
209 		UserInterfaceListener::QUIT_OPTION_ASK_KILL_TEAM);
210 }
211 
212 
213 void
ThreadAdded(const Team::ThreadEvent & event)214 ReportUserInterface::ThreadAdded(const Team::ThreadEvent& event)
215 {
216 	::Thread* thread = event.GetThread();
217 	if (thread->ID() != fTargetThread)
218 		return;
219 
220 	if (thread->State() != THREAD_STATE_STOPPED)
221 		fListener->ThreadActionRequested(thread->ID(), MSG_THREAD_STOP);
222 	else
223 		release_sem(fShowSemaphore);
224 }
225 
226 
227 void
ThreadStateChanged(const Team::ThreadEvent & event)228 ReportUserInterface::ThreadStateChanged(const Team::ThreadEvent& event)
229 {
230 	::Thread* thread = event.GetThread();
231 	if (thread->ID() != fTargetThread)
232 		return;
233 	else if (thread->State() == THREAD_STATE_STOPPED)
234 		release_sem(fShowSemaphore);
235 }
236 
237 
238 void
DebugReportChanged(const Team::DebugReportEvent & event)239 ReportUserInterface::DebugReportChanged(const Team::DebugReportEvent& event)
240 {
241 	if (event.GetFinalStatus() == B_OK)
242 		printf("Debug report saved to %s\n", event.GetReportPath());
243 	else {
244 		fprintf(stderr, "Failed to write debug report: %s\n", strerror(
245 				event.GetFinalStatus()));
246 	}
247 	release_sem(fReportSemaphore);
248 }
249