Files
QNX/services/slogger/main.c
2025-08-20 19:02:58 +08:00

187 lines
5.2 KiB
C

/*
* $QNXLicenseC:
* Copyright 2007, QNX Software Systems. All Rights Reserved.
*
* You must obtain a written license from and pay applicable license fees to QNX
* Software Systems before you may reproduce, modify or distribute this software,
* or any work that includes all or part of this software. Free development
* licenses are available for evaluation and non-commercial purposes. For more
* information visit http://licensing.qnx.com or email licensing@qnx.com.
*
* This file may contain contributions from others. Please review this entire
* file for other proprietary rights or license notices, as well as the QNX
* Development Suite License Guide at http://licensing.qnx.com/license-guide/
* for other information.
* $
*/
#include "externs.h"
int main(int argc, char *argv[]) {
dispatch_t *dpp;
resmgr_context_t *ctp;
resmgr_attr_t res_attr;
resmgr_connect_funcs_t connect_funcs1;
resmgr_connect_funcs_t connect_funcs2;
resmgr_io_funcs_t io_funcs1;
resmgr_io_funcs_t io_funcs2;
struct slogdev *trp;
int daemon_flag = 0;
// Parse any options.
options(argc, argv);
//
// Buffer allocation.
// The design puts all the data structures in one big contiguious
// chunk of memory. Makes it easy to analyze if it was in a memory
// mapped SRAM card which survives a crash or power failure.
//
trp = &SlogDev;
trp->beg = malloc(NumInts*sizeof(int));
trp->end = trp->beg + NumInts;
if(trp->beg == NULL) {
fprintf(stderr, "%s: Insufficient memory to allocate buffers.\n", __progname);
exit(EXIT_FAILURE);
}
slogger_init(trp);
// Create a dispatch context to receive messages.
if((dpp = dispatch_create()) == NULL) {
fprintf(stderr, "%s: Unable to allocate dispatch context\n", __progname);
exit(EXIT_FAILURE);
}
// Init resmgr attributes
memset(&res_attr, 0, sizeof res_attr);
res_attr.nparts_max = 2;
res_attr.msg_max_size = 1024;
// Init funcs for handling /dev/slog messages
iofunc_func_init(_RESMGR_CONNECT_NFUNCS, &connect_funcs1, _RESMGR_IO_NFUNCS, &io_funcs1);
connect_funcs1.unlink = io_unlink;
io_funcs1.read = io_read;
io_funcs1.write = io_write;
io_funcs1.unblock = io_unblock;
// Create /dev/slog in the pathname space. At this point we can get opens.
iofunc_attr_init(&trp->attr, S_IFCHR | 0666, 0, 0);
if((trp->id = resmgr_attach(dpp, &res_attr, "/dev/slog", _FTYPE_ANY, _RESMGR_FLAG_SELF,
&connect_funcs1, &io_funcs1, &trp->attr)) == -1) {
fprintf(stderr, "%s: Unable to allocate device %s (%s)\n", __progname, "/dev/slog", strerror(errno));
exit(EXIT_FAILURE);
}
// Init funcs for handling /dev/slog messages
iofunc_func_init(_RESMGR_CONNECT_NFUNCS, &connect_funcs2, _RESMGR_IO_NFUNCS, &io_funcs2);
io_funcs2.write = io_console_write;
// Create /dev/console in the pathname space. At this point we can get opens.
if(resmgr_attach(dpp, &res_attr, "/dev/console", _FTYPE_ANY, 0,
&connect_funcs2, &io_funcs2, &trp->attr) == -1) {
fprintf(stderr, "%s: Unable to allocate device %s (%s)\n", __progname, "/dev/console", strerror(errno));
exit(EXIT_FAILURE);
}
// If a logfile was specified then create a thread to write it
if(LogFname) {
sigset_t signalset;
if(pthread_create(0, NULL, &logger, NULL) != 0) {
fprintf(stderr, "%s: Unable to create logger thread.\n", __progname);
exit(EXIT_FAILURE);
}
// We want the logger thread to catch signals. Not us!
sigemptyset(&signalset);
sigfillset(&signalset);
pthread_sigmask(SIG_BLOCK, &signalset, NULL);
}
// Run in backgound
if(Verbose) {
daemon_flag = PROCMGR_DAEMON_NODEVNULL;
}
if (procmgr_daemon(EXIT_SUCCESS, daemon_flag) == -1) {
fprintf(stderr, "%s: Couldn't become daemon.\n", argv[0]);
}
// Slogger is single-threaded
ctp = resmgr_context_alloc(dpp);
for(;;) {
if((ctp = resmgr_block(ctp)) == NULL)
exit(EXIT_FAILURE);
resmgr_handler(ctp);
}
exit(EXIT_SUCCESS);
}
void
slogger_init(struct slogdev *trp) {
memset(trp->beg, 0, NumInts * sizeof(trp->beg[0]));
trp->get = trp->put = trp->beg;
trp->cnt = 0;
}
//
// We override the default functions for allocating the OCB so we can get
// control and build a list of open for reads on /dev/slog. We could
// have also hooked the io_open/io_close function but this was easier.
//
IOFUNC_OCB_T *iofunc_ocb_calloc(resmgr_context_t *ctp, IOFUNC_ATTR_T *attr) {
struct slogdev *trp = (struct slogdev *) attr;
struct ocbs *ocbl;
IOFUNC_OCB_T *ocb;
if((ocb = calloc(1, sizeof(*ocb)))) {
// Only keep a list of open for reads on /dev/slog.
// The trp->id contains the id for /dev/slog.
if(trp->id != ctp->id || (((io_open_t *)ctp->msg)->connect.ioflag & _IO_FLAG_RD) == 0)
return(ocb);
// We keep a list of readers which is need to check for overflow..
if((ocbl = calloc(1, sizeof(*ocbl)))) {
ocbl->ocb = ocb;
ocbl->next = trp->ocbs;
trp->ocbs = ocbl;
return(ocb);
}
free(ocb);
}
return(NULL);
}
//
// We also hook the free function which is called on a close.
//
void iofunc_ocb_free(IOFUNC_OCB_T *ocb) {
struct slogdev *trp = (struct slogdev *) ocb->attr;
struct ocbs *cur, *prev;
prev = (struct ocbs *) &trp->ocbs;
for(; (cur = prev->next) ; prev = cur)
if(cur->ocb == ocb) {
prev->next = cur->next;
free(cur);
break;
}
free(ocb);
}
__SRCVERSION("main.c $Rev: 153052 $");