source: drsdaq/drsdaq.cpp@ 189

Last change on this file since 189 was 182, checked in by ogrimm, 15 years ago
Updates to DIM integration
File size: 9.2 KB
Line 
1/**************************************************************\
2
3 drsdaq.cpp
4
5 Main program for DRS CTX DAQ system. Global initialization,
6 starts threads for console input and socket interface.
7
8 Sebastian Commichau, Oliver Grimm
9
10\**************************************************************/
11
12#define DEFAULT_CONFIG "../config/DRSDAQ.conf" // Default configuration file
13#define LOCKFILE "/tmp/CT3_DAQ_LOCK"
14
15#include <stdio.h>
16#include <signal.h>
17#include <pthread.h>
18#include <sys/socket.h>
19#include <netdb.h>
20#include <arpa/inet.h>
21#include <readline/readline.h>
22#include <readline/history.h>
23
24#include "DAQReadout.h"
25#include "HVFeedback.h"
26
27// Function prototypes
28void ConsoleCommand(DAQReadout *);
29void CCCommand(DAQReadout *);
30void SignalHandler(int);
31void CrashHandler(int);
32void ExitFunction();
33
34// ================
35// Main program
36// ================
37//
38// Several unlikely system call failures are handled via throwing an exception.
39
40int main(int argc, char *argv[]) {
41
42 char str[MAX_COM_SIZE];
43 pthread_t thread_ConsoleCommand, thread_CCCommand;
44 int LockDescriptor;
45
46 // writev() in DAQ thread needs to be able to write at least 3 chunks
47 if(IOV_MAX < 3) {
48 printf("Fatal error: IOV_MAX is less than 3, cannot use writev() to write event data.\n");
49 exit(EXIT_FAILURE);
50 }
51
52 // Interpret command line (do before lockfile creation in case of exit())
53 if((argc==3 && strcmp(argv[1],"-c")!=0) || argc==2) {
54 printf("Usage: %s [-c <ConfigFile>] Default file is \"%s\"\n", argv[0], DEFAULT_CONFIG);
55 exit(EXIT_SUCCESS);
56 }
57
58 // Assure only one instance of program runs (lock creator written to log file)
59 if((LockDescriptor = open(LOCKFILE,O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)) == -1) {
60 if(errno==EEXIST) {
61 printf("Error: Lock file already existing\n");
62 sprintf(str,"paste %s -s -d ' '",LOCKFILE);
63 system(str);
64 }
65 else printf("Could not create lock file %s (%s)\n", LOCKFILE, strerror(errno));
66 exit(EXIT_FAILURE);
67 }
68 close(LockDescriptor);
69 sprintf(str,"echo Created >%s; date >>%s; echo by $USER@$HOSTNAME >>%s",LOCKFILE,LOCKFILE,LOCKFILE);
70 system(str);
71
72 system("clear");
73 printf("\n*** DRS readout built %s, %s (revision %s) *** \n\n",__DATE__, __TIME__, REVISION);
74
75 // Set signal handlers
76 signal(SIGUSR1, &SignalHandler);
77 siginterrupt (SIGUSR1, true); // Set SIGUSR1 to interrupt (and not restart) blocking system calls
78 signal(SIGQUIT, &CrashHandler);
79 signal(SIGILL, &CrashHandler);
80 signal(SIGABRT, &CrashHandler);
81 signal(SIGFPE, &CrashHandler);
82 signal(SIGSEGV, &CrashHandler);
83 signal(SIGBUS, &CrashHandler);
84 signal(SIGTERM, &CrashHandler);
85 signal(SIGINT, &CrashHandler);
86 signal(SIGHUP, &CrashHandler);
87 atexit(&ExitFunction);
88
89 // Construct main instance and create mutex for thread synchronization
90 DAQReadout dreadout;
91 if (pthread_mutex_init(&dreadout.control_mutex, NULL) != 0) {
92 perror("pthread_mutex_init failed");
93 throw;
94 }
95
96 // Create threads
97 if (pthread_mutex_init(&dreadout.control_mutex, NULL) != 0) {
98 perror("pthread_mutex_init failed");
99 throw;
100 }
101 if ((pthread_create(&thread_ConsoleCommand, NULL, (void * (*)(void *)) ConsoleCommand,(void *) &dreadout)) != 0) {
102 perror("pthread_create failed with console thread");
103 throw;
104 }
105 if ((pthread_create(&thread_CCCommand, NULL, (void * (*)(void *)) CCCommand,(void *) &dreadout)) != 0) {
106 perror("pthread_create failed with socket thread");
107 dreadout.SocketThread = NULL;
108 }
109 else dreadout.SocketThread = &thread_CCCommand; // Thread should be accessible for sending signals
110
111 // Wait for threads to quit
112 pthread_join(thread_ConsoleCommand, NULL);
113 if(dreadout.SocketThread != NULL) pthread_join(thread_CCCommand, NULL);
114
115 // Destruct mutex and main instance
116 pthread_mutex_destroy (&dreadout.control_mutex);
117 dreadout.~DAQReadout();
118
119 // Remove lockfile
120 if (remove(LOCKFILE)==-1) {
121 printf("Could not remove lock file %s (%s)\n", LOCKFILE, strerror(errno));
122 exit(EXIT_FAILURE);
123 }
124 exit(EXIT_SUCCESS);
125}
126
127
128/********************************************************************\
129
130 ConsoleCommand thread
131
132 Handle console input using readline library functions to allow
133 line editing and history capability
134
135\********************************************************************/
136
137void ConsoleCommand(DAQReadout *m) {
138
139 char *Command;
140
141 while (!m->Exit) {
142
143 // Assemble prompt
144 if (m->NumBoards == 0) snprintf(m->Prompt,sizeof(m->Prompt),"\rDAQ> ");
145 else if (m->FirstBoard == m->LastBoard) snprintf(m->Prompt,sizeof(m->Prompt),"\rDAQ|B%d> ",m->FirstBoard);
146 else snprintf(m->Prompt,sizeof(m->Prompt),"\rDAQ|B%d-%d> ",m->FirstBoard,m->LastBoard);
147
148 // Read Command
149 Command = readline(m->Prompt);
150 if (Command == NULL) {
151 m->PrintMessage("Error reading command line input\n");
152 continue;
153 }
154 if(strlen(Command)>0) add_history(Command);
155
156 // Log command
157 m->PrintMessage(MsgToLog, "CONSOLE> %s\n", Command);
158
159 // Process command
160 pthread_mutex_lock(&m->control_mutex);
161 m->CommandControl(Command);
162 pthread_mutex_unlock(&m->control_mutex);
163
164 free(Command);
165 }
166}
167
168
169
170/********************************************************************\
171
172 CCCommand thread
173
174 Listen to commands from socket (Central Control)
175
176 This thread will block execution in the accept() and read() socket function
177 while waiting for a connection or data. If the exit function is invoked through
178 keyboard command, these blocking functions are interrupted by raising the signal
179 SIGUSR1. Testing on errno=EINTR indicates this termination. The dummy signal
180 handler below is needed to prevent the standard thread termination occurring
181 when this signal is received.
182
183\********************************************************************/
184
185void CCCommand(DAQReadout *m) {
186
187 int ServerSocket,ConnectionSocket,ReadResult;
188 struct sockaddr_in SocketAddress, ClientAddress;
189 struct hostent *ClientName;
190 socklen_t SizeClientAddress=sizeof(ClientAddress);
191 char Command[MAX_COM_SIZE];
192
193 // Set up server socket
194 if ((ServerSocket = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
195 m->PrintMessage("Could not open server socket, no remote connection possible (%s).\n", strerror(errno));
196 return;
197 }
198 // Allows immediate reuse of socket after closing (circumvents TIME_WAIT)
199 int Value=1;
200 if (setsockopt(ServerSocket, SOL_SOCKET, SO_REUSEADDR, (char *) &Value, sizeof (Value)) == -1) {
201 m->PrintMessage("Warning: Could not set server socket option SO_REUSEADDR (%s)\n", strerror(errno));
202 }
203
204 SocketAddress.sin_family = PF_INET;
205 SocketAddress.sin_port = htons((unsigned short) m->fCCPort);
206 SocketAddress.sin_addr.s_addr = INADDR_ANY;
207
208 if (bind(ServerSocket, (struct sockaddr *) &SocketAddress, sizeof(SocketAddress)) == -1)
209 {
210 m->PrintMessage("Could not bind port to socket (%s)\n", strerror(errno));
211 close(ServerSocket);
212 return;
213 }
214 if (listen(ServerSocket, 0) == -1) {
215 m->PrintMessage("Could not set socket to listening (%s)\n", strerror(errno));
216 close(ServerSocket);
217 return;
218 }
219
220 // Looping to wait for incoming connection
221 while (!m->Exit) {
222 if ((ConnectionSocket = accept(ServerSocket, (struct sockaddr *) &ClientAddress, &SizeClientAddress)) == -1) {
223 if (errno!=EINTR) m->PrintMessage("Failed to accept incoming connection (%s)\n", strerror(errno));
224 close(ServerSocket);
225 return;
226 }
227
228 ClientName = gethostbyaddr((char *) &ClientAddress.sin_addr ,sizeof(struct sockaddr_in),AF_INET);
229 m->PrintMessage("Connected to client at %s (%s).\n", inet_ntoa(ClientAddress.sin_addr), ClientName!=NULL ? ClientName->h_name:"name unknown");
230 m->Socket = ConnectionSocket;
231
232 // Looping as long as client exists and program not terminated
233 while (!m->Exit) {
234
235 // Try to read command from socket
236 memset(Command,0,sizeof(Command));
237 ReadResult = read(ConnectionSocket, Command, MAX_COM_SIZE);
238 if (ReadResult==0) break; // Client not exisiting anymore
239 if (ReadResult==-1) {
240 if (errno!=EINTR) m->PrintMessage("Error read from socket (%s)\n", strerror(errno));
241 break;
242 }
243 if (Command[strlen(Command)-1]=='\n') Command[strlen(Command)-1]='\0'; // Remove trailing newline
244
245 // Log command
246 m->PrintMessage(MsgToConsole|MsgToLog, "SOCKET> %s\n", Command);
247
248 // Process command
249 pthread_mutex_lock(&m->control_mutex);
250 m->CmdFromSocket = true;
251 m->CommandControl(Command);
252 m->CmdFromSocket = false;
253 pthread_mutex_unlock(&m->control_mutex);
254 }
255
256 m->Socket = -1;
257 m->PrintMessage("Disconnected from client.\n");
258 close(ConnectionSocket);
259 }
260 close(ServerSocket);
261 m->PrintMessage("Server socket closed.\n");
262}
263
264
265/********************************************************************\
266
267 Signal handlers
268
269\********************************************************************/
270
271// Remove lock file before running default signal code
272void CrashHandler(int Signal) {
273 remove(LOCKFILE);
274 printf("Caught signal number %d. Removing lockfile and performing standard signal action. Good luck.\n",Signal);
275 signal(Signal, SIG_DFL);
276 raise(Signal);
277}
278
279// Dummy signal handler to return from blocking syscalls
280void SignalHandler(int Signal) {
281 return;
282}
283
284// This function will be implicitly called by exit()
285void ExitFunction() {
286 remove(LOCKFILE);
287 return;
288}
Note: See TracBrowser for help on using the repository browser.