source: drsdaq/drsdaq.cpp@ 97

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