/******************************************************************** * Description: rtapi_support.c * This file, 'rtapi_support.c', implements the messaging * functions for both kernel and userland thread * systems. See rtapi.h for more info. * * Other than the rest of RTAPI, these functions are linked * into the instance module which is loaded before rtapi.so/ko * so they are available and message level set before * RTAPI starts up * * Copyright 2006-2013 Various Authors * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ********************************************************************/ #include "config.h" #include "rtapi.h" #include "rtapi/shmdrv/shmdrv.h" #include "ring.h" #define RTPRINTBUFFERLEN 1024 #ifdef MODULE #include "rtapi_app.h" #include <stdarg.h> /* va_* */ #include <linux/kernel.h> /* kernel's vsnprintf */ #define MSG_ORIGIN MSG_KERNEL #else /* user land */ #include <stdio.h> /* libc's vsnprintf() */ #include <sys/types.h> #include <unistd.h> #ifdef RTAPI #define MSG_ORIGIN MSG_RTUSER #else #define MSG_ORIGIN MSG_ULAPI #endif #endif // these message levels are used in RTAPI and ULAPI // respectively until the global segment is attached; // thereafter switch to using the message levels from there. #ifdef RTAPI static int rt_msg_level = RTAPI_MSG_INFO; // RTAPI (u+k) #else static int ulapi_msg_level = RTAPI_MSG_INFO; // ULAPI #endif #ifdef ULAPI ringbuffer_t rtapi_message_buffer; // rtapi_message ring access strcuture # else extern ringbuffer_t rtapi_message_buffer; #endif static char logtag[TAGSIZE]; // switch to exclusively using the ringbuffer from RT #define USE_MESSAGE_RING 1 typedef struct { rtapi_msgheader_t hdr; char buf[RTPRINTBUFFERLEN]; } rtapi_msg_t; void vs_ring_write(msg_level_t level, const char *format, va_list ap) { int n; rtapi_msg_t logmsg; #if defined(RTAPI) && defined(BUILD_SYS_USER_DSO) static pid_t rtapi_pid; if (rtapi_pid == 0) rtapi_pid = getpid(); #endif if (global_data) { // one-time initialisation if (!rtapi_message_buffer.header) { ringbuffer_init(&global_data->rtapi_messages, &rtapi_message_buffer); } logmsg.hdr.origin = MSG_ORIGIN; #if defined(RTAPI) && defined(BUILD_SYS_KBUILD) logmsg.hdr.pid = 0; #endif #if defined(RTAPI) && defined(BUILD_SYS_USER_DSO) logmsg.hdr.pid = rtapi_pid; #endif #if defined(ULAPI) logmsg.hdr.pid = getpid(); #endif logmsg.hdr.level = level; logmsg.hdr.encoding = MSG_ASCII; strncpy(logmsg.hdr.tag, logtag, sizeof(logmsg.hdr.tag)); // do format outside critical section n = vsnprintf(logmsg.buf, RTPRINTBUFFERLEN, format, ap); if (rtapi_message_buffer.header->use_wmutex && rtapi_mutex_try(&rtapi_message_buffer.header->wmutex)) { global_data->error_ring_locked++; return; } // use copying writer to shorten criticial section record_write(&rtapi_message_buffer, (void *) &logmsg, sizeof(rtapi_msgheader_t) + n + 1); // trailing zero if (rtapi_message_buffer.header->use_wmutex) rtapi_mutex_give(&rtapi_message_buffer.header->wmutex); } } #ifdef MODULE void default_rtapi_msg_handler(msg_level_t level, const char *fmt, va_list ap) { char buf[RTPRINTBUFFERLEN]; vsnprintf(buf, RTPRINTBUFFERLEN, fmt, ap); vs_ring_write(level, buf, ap); } #else /* user land */ void default_rtapi_msg_handler(msg_level_t level, const char *fmt, va_list ap) { // during startup the global segment might not be // available yet, so use stderr until then if (MMAP_OK(global_data)) { vs_ring_write(level, fmt, ap); } else { vfprintf(stderr, fmt, ap); } }
int ulapi_main(int instance, int flavor, global_data_t *global) { int retval = 0; int rtapikey; int size = 0; rtapi_instance = instance; // from here on global within ulapi.so // shm_common_init(); // common shared memory API needs this // the HAL library constructor already has the global // shm segment attached, so no need to do it again here // since we're not using the rtapi_app_init()/rtapi_app_exit() // calling conventions might as well pass it it // this sets global_data for use within ulapi.so which // has a disjoint symbol namespace from hal_lib global_data = global; rtapi_print_msg(RTAPI_MSG_DBG,"ULAPI:%d %s %s init\n", rtapi_instance, rtapi_get_handle()->thread_flavor_name, GIT_VERSION); if (rtapi_switch->thread_flavor_flags & FLAVOR_RTAPI_DATA_IN_SHM) { rtapikey = OS_KEY(RTAPI_KEY, rtapi_instance); // attach to existing RTAPI segment // not all thread flavors actuall might use it if ((retval = shm_common_new(rtapikey, &size, rtapi_instance, (void **) &rtapi_data, 0))) { rtapi_print_msg(RTAPI_MSG_ERR, "ULAPI:%d ERROR: cannot attach rtapi" " segment key=0x%x %s\n", rtapi_instance, rtapikey, strerror(-retval)); } if (size != sizeof(rtapi_data_t)) { rtapi_print_msg(RTAPI_MSG_ERR, "ULAPI:%d ERROR: unexpected rtapi shm size:" " expected: %zu actual: %d\n", rtapi_instance, sizeof(rtapi_data_t), size); return -EINVAL; } if (MMAP_OK(global_data) && MMAP_OK(rtapi_data)) { rtapi_print_msg(RTAPI_MSG_DBG, "ULAPI:%d msglevel=%d/%d halsize=%d" " %s startup %s\n", rtapi_instance, global_data->rt_msg_level, global_data->user_msg_level, global_data->hal_size, GIT_VERSION, retval ? "FAILED" : "OK"); } else { rtapi_print_msg(RTAPI_MSG_DBG, "ULAPI:%d init failed, realtime not running?" " global=%p rtapi=%p\n", rtapi_instance, global_data, rtapi_data); } } return retval; }