2013-11-27 16:28:31 +01:00
/*
2013-06-18 17:21:38 +02:00
* Copyright ( C ) 2013 Freie Universität Berlin
2010-09-22 15:10:42 +02:00
*
2013-11-22 20:47:05 +01:00
* This file is subject to the terms and conditions of the GNU Lesser General
2013-06-18 17:21:38 +02:00
* Public License . See the file LICENSE in the top level directory for more
* details .
2013-11-27 16:28:31 +01:00
*/
/**
* @ ingroup core_msg
2010-09-22 15:10:42 +02:00
* @ {
2013-11-27 16:28:31 +01:00
*
2010-09-22 15:10:42 +02:00
* @ file
2013-11-27 16:28:31 +01:00
* @ brief Kernel messaging implementation
*
* @ author Freie Universität Berlin , Computer Systems & Telematics , FeuerWhere project
2014-01-28 11:50:12 +01:00
* @ author Kaspar Schleiser < kaspar @ schleiser . de >
2013-11-27 16:28:31 +01:00
* @ author Oliver Hahm < oliver . hahm @ inria . fr >
*
2010-09-22 15:10:42 +02:00
* @ }
*/
2013-12-16 17:54:58 +01:00
# include <stddef.h>
# include <inttypes.h>
2010-09-22 15:10:42 +02:00
# include "kernel.h"
2010-10-28 11:22:57 +02:00
# include "sched.h"
2010-09-22 15:10:42 +02:00
# include "msg.h"
# include "queue.h"
# include "tcb.h"
2013-12-16 17:54:58 +01:00
# include "irq.h"
# include "cib.h"
2010-09-22 15:10:42 +02:00
# include "flags.h"
2013-07-24 00:36:06 +02:00
# define ENABLE_DEBUG (0)
2010-09-22 15:10:42 +02:00
# include "debug.h"
2013-07-16 15:25:11 +02:00
# include "thread.h"
2010-09-22 15:10:42 +02:00
2013-07-05 23:34:11 +02:00
static int _msg_receive ( msg_t * m , int block ) ;
2013-06-20 18:18:29 +02:00
static int queue_msg ( tcb_t * target , msg_t * m )
{
int n = cib_put ( & ( target - > msg_queue ) ) ;
2010-11-26 14:21:48 +01:00
2013-06-24 22:37:35 +02:00
if ( n ! = - 1 ) {
2013-06-20 18:18:29 +02:00
target - > msg_array [ n ] = * m ;
return 1 ;
}
2010-11-26 14:21:48 +01:00
2013-06-20 18:18:29 +02:00
return 0 ;
2010-11-26 14:21:48 +01:00
}
2013-06-20 18:18:29 +02:00
int msg_send ( msg_t * m , unsigned int target_pid , bool block )
{
2013-06-24 22:37:35 +02:00
if ( inISR ( ) ) {
2010-09-22 15:10:42 +02:00
return msg_send_int ( m , target_pid ) ;
}
2013-06-20 18:18:29 +02:00
tcb_t * target = ( tcb_t * ) sched_threads [ target_pid ] ;
2010-09-22 15:10:42 +02:00
2010-10-28 11:22:57 +02:00
m - > sender_pid = thread_pid ;
2013-06-20 18:18:29 +02:00
2013-06-24 22:37:35 +02:00
if ( m - > sender_pid = = target_pid ) {
2010-11-26 14:21:48 +01:00
return - 1 ;
}
2010-09-22 15:10:42 +02:00
2013-06-24 22:37:35 +02:00
if ( target = = NULL ) {
2010-09-22 15:10:42 +02:00
return - 1 ;
}
2010-11-26 14:21:48 +01:00
dINT ( ) ;
2013-06-20 18:18:29 +02:00
2014-02-12 19:09:50 +01:00
DEBUG ( " msg_send() %s:%i: Sending from %i to %i. block=%i src->state=%i target->state=%i \n " , __FILE__ , __LINE__ , thread_pid , target_pid , block , active_thread - > status , target - > status ) ;
2013-12-02 16:38:39 +01:00
if ( target - > status ! = STATUS_RECEIVE_BLOCKED ) {
2014-02-12 19:09:50 +01:00
DEBUG ( " msg_send() %s:%i: Target %i is not RECEIVE_BLOCKED. \n " , __FILE__ , __LINE__ , target_pid ) ;
2013-06-24 22:37:35 +02:00
if ( target - > msg_array & & queue_msg ( target , m ) ) {
2014-02-12 19:09:50 +01:00
DEBUG ( " msg_send() %s:%i: Target %i has a msg_queue. Queueing message. \n " , __FILE__ , __LINE__ , target_pid ) ;
2010-11-26 14:21:48 +01:00
eINT ( ) ;
return 1 ;
}
2013-06-24 22:37:35 +02:00
if ( ! block ) {
2013-10-27 08:37:18 +01:00
DEBUG ( " msg_send: %s: Receiver not waiting, block=%u \n " , active_thread - > name , block ) ;
2010-09-22 15:10:42 +02:00
eINT ( ) ;
return 0 ;
}
2013-10-27 08:37:18 +01:00
DEBUG ( " msg_send: %s: send_blocked. \n " , active_thread - > name ) ;
2010-09-22 15:10:42 +02:00
queue_node_t n ;
2010-10-28 11:22:57 +02:00
n . priority = active_thread - > priority ;
n . data = ( unsigned int ) active_thread ;
2013-08-01 16:40:34 +02:00
n . next = NULL ;
2013-10-27 08:37:18 +01:00
DEBUG ( " msg_send: %s: Adding node to msg_waiters: \n " , active_thread - > name ) ;
2010-09-22 15:10:42 +02:00
2010-11-26 14:21:48 +01:00
queue_priority_add ( & ( target - > msg_waiters ) , & n ) ;
2010-09-22 15:10:42 +02:00
2010-10-28 11:22:57 +02:00
active_thread - > wait_data = ( void * ) m ;
2010-09-22 15:10:42 +02:00
int newstatus ;
2013-06-20 18:18:29 +02:00
2013-06-24 22:37:35 +02:00
if ( active_thread - > status = = STATUS_REPLY_BLOCKED ) {
2010-09-22 15:10:42 +02:00
newstatus = STATUS_REPLY_BLOCKED ;
2013-06-20 18:18:29 +02:00
}
else {
2010-09-22 15:10:42 +02:00
newstatus = STATUS_SEND_BLOCKED ;
}
2013-12-04 20:36:21 +01:00
sched_set_status ( ( tcb_t * ) active_thread , newstatus ) ;
2013-06-20 18:18:29 +02:00
2013-10-27 08:37:18 +01:00
DEBUG ( " msg_send: %s: Back from send block. \n " , active_thread - > name ) ;
2013-06-20 18:18:29 +02:00
}
else {
2013-11-03 15:46:13 +01:00
DEBUG ( " msg_send: %s: Direct msg copy from %i to %i. \n " , active_thread - > name , thread_getpid ( ) , target_pid ) ;
2010-09-22 15:10:42 +02:00
/* copy msg to target */
2013-06-20 18:18:29 +02:00
msg_t * target_message = ( msg_t * ) target - > wait_data ;
2010-09-22 15:10:42 +02:00
* target_message = * m ;
2013-12-04 20:36:21 +01:00
sched_set_status ( target , STATUS_PENDING ) ;
2010-09-22 15:10:42 +02:00
}
eINT ( ) ;
2010-10-28 11:22:57 +02:00
thread_yield ( ) ;
2010-09-22 15:10:42 +02:00
2010-11-26 14:21:48 +01:00
return 1 ;
2010-09-22 15:10:42 +02:00
}
2013-06-20 18:18:29 +02:00
int msg_send_int ( msg_t * m , unsigned int target_pid )
{
tcb_t * target = ( tcb_t * ) sched_threads [ target_pid ] ;
2010-09-22 15:10:42 +02:00
2013-12-02 16:38:39 +01:00
if ( target - > status = = STATUS_RECEIVE_BLOCKED ) {
2013-10-27 08:37:18 +01:00
DEBUG ( " msg_send_int: Direct msg copy from %i to %i. \n " , thread_getpid ( ) , target_pid ) ;
2010-09-22 15:10:42 +02:00
2010-09-24 16:24:13 +02:00
m - > sender_pid = target_pid ;
2010-09-22 15:10:42 +02:00
/* copy msg to target */
2013-06-20 18:18:29 +02:00
msg_t * target_message = ( msg_t * ) target - > wait_data ;
2010-09-22 15:10:42 +02:00
* target_message = * m ;
2013-12-04 20:36:21 +01:00
sched_set_status ( target , STATUS_PENDING ) ;
2010-09-22 15:10:42 +02:00
2010-10-28 11:22:57 +02:00
sched_context_switch_request = 1 ;
2010-09-22 15:10:42 +02:00
return 1 ;
2013-06-20 18:18:29 +02:00
}
else {
2013-10-27 08:37:18 +01:00
DEBUG ( " msg_send_int: Receiver not waiting. \n " ) ;
2010-11-26 14:21:48 +01:00
return ( queue_msg ( target , m ) ) ;
2010-09-22 15:10:42 +02:00
}
}
2013-06-20 18:18:29 +02:00
int msg_send_receive ( msg_t * m , msg_t * reply , unsigned int target_pid )
{
2010-09-22 15:10:42 +02:00
dINT ( ) ;
2011-03-08 11:43:21 +01:00
tcb_t * me = ( tcb_t * ) sched_threads [ thread_pid ] ;
2013-12-04 20:36:21 +01:00
sched_set_status ( me , STATUS_REPLY_BLOCKED ) ;
2010-09-22 15:10:42 +02:00
me - > wait_data = ( void * ) reply ;
/* msg_send blocks until reply received */
2013-06-20 18:18:29 +02:00
2013-08-01 22:03:55 +02:00
return msg_send ( m , target_pid , true ) ;
2010-09-22 15:10:42 +02:00
}
2013-06-20 18:18:29 +02:00
int msg_reply ( msg_t * m , msg_t * reply )
{
2010-09-24 16:24:13 +02:00
int state = disableIRQ ( ) ;
2013-06-20 18:18:29 +02:00
tcb_t * target = ( tcb_t * ) sched_threads [ m - > sender_pid ] ;
2013-09-11 19:39:34 +02:00
if ( ! target ) {
2013-10-27 08:37:18 +01:00
DEBUG ( " msg_reply(): %s: Target \" % " PRIu16 " \" not existing...dropping msg! \n " , active_thread - > name , m - > sender_pid ) ;
2013-09-11 19:39:34 +02:00
return - 1 ;
}
2013-06-24 22:37:35 +02:00
if ( target - > status ! = STATUS_REPLY_BLOCKED ) {
2013-10-27 08:37:18 +01:00
DEBUG ( " msg_reply(): %s: Target \" %s \" not waiting for reply. " , active_thread - > name , target - > name ) ;
2010-09-24 16:24:13 +02:00
restoreIRQ ( state ) ;
2010-09-22 15:10:42 +02:00
return - 1 ;
}
2013-06-20 18:18:29 +02:00
2013-10-27 08:37:18 +01:00
DEBUG ( " msg_reply(): %s: Direct msg copy. \n " , active_thread - > name ) ;
2010-09-22 15:10:42 +02:00
/* copy msg to target */
2013-06-20 18:18:29 +02:00
msg_t * target_message = ( msg_t * ) target - > wait_data ;
2010-10-28 10:12:45 +02:00
* target_message = * reply ;
2013-12-04 20:36:21 +01:00
sched_set_status ( target , STATUS_PENDING ) ;
2010-09-24 16:24:13 +02:00
restoreIRQ ( state ) ;
2010-10-28 11:22:57 +02:00
thread_yield ( ) ;
2010-09-22 15:10:42 +02:00
return 1 ;
}
2013-06-20 18:18:29 +02:00
int msg_reply_int ( msg_t * m , msg_t * reply )
{
tcb_t * target = ( tcb_t * ) sched_threads [ m - > sender_pid ] ;
2013-06-24 22:37:35 +02:00
if ( target - > status ! = STATUS_REPLY_BLOCKED ) {
2013-10-27 08:37:18 +01:00
DEBUG ( " msg_reply_int(): %s: Target \" %s \" not waiting for reply. " , active_thread - > name , target - > name ) ;
2010-09-24 16:24:13 +02:00
return - 1 ;
}
2013-06-20 18:18:29 +02:00
msg_t * target_message = ( msg_t * ) target - > wait_data ;
2010-11-03 11:37:20 +01:00
* target_message = * reply ;
2013-12-04 20:36:21 +01:00
sched_set_status ( target , STATUS_PENDING ) ;
2010-10-28 11:22:57 +02:00
sched_context_switch_request = 1 ;
2010-09-24 16:24:13 +02:00
return 1 ;
}
2013-07-05 19:22:29 +02:00
int msg_try_receive ( msg_t * m )
{
2013-07-09 13:41:08 +02:00
return _msg_receive ( m , 0 ) ;
2013-07-05 19:22:29 +02:00
}
2013-06-20 18:18:29 +02:00
int msg_receive ( msg_t * m )
2013-07-05 19:22:29 +02:00
{
2013-07-09 13:41:08 +02:00
return _msg_receive ( m , 1 ) ;
2013-07-05 19:22:29 +02:00
}
2013-07-09 13:41:08 +02:00
static int _msg_receive ( msg_t * m , int block )
2013-06-20 18:18:29 +02:00
{
2010-09-22 15:10:42 +02:00
dINT ( ) ;
2013-10-27 08:37:18 +01:00
DEBUG ( " _msg_receive: %s: _msg_receive. \n " , active_thread - > name ) ;
2010-09-22 15:10:42 +02:00
2011-03-08 11:43:21 +01:00
tcb_t * me = ( tcb_t * ) sched_threads [ thread_pid ] ;
2010-09-22 15:10:42 +02:00
2013-12-02 16:56:43 +01:00
int queue_index = - 1 ;
2013-06-20 18:18:29 +02:00
2013-06-24 22:37:35 +02:00
if ( me - > msg_array ) {
2013-12-02 16:56:43 +01:00
queue_index = cib_get ( & ( me - > msg_queue ) ) ;
2010-11-26 15:02:15 +01:00
}
2013-07-05 19:22:29 +02:00
/* no message, fail */
2013-12-02 16:56:43 +01:00
if ( ( ! block ) & & ( queue_index = = - 1 ) ) {
2013-07-05 19:22:29 +02:00
return - 1 ;
}
2013-12-02 16:56:43 +01:00
if ( queue_index > = 0 ) {
2013-10-27 08:37:18 +01:00
DEBUG ( " _msg_receive: %s: _msg_receive(): We've got a queued message. \n " , active_thread - > name ) ;
2013-12-02 16:56:43 +01:00
* m = me - > msg_array [ queue_index ] ;
2013-06-20 18:18:29 +02:00
}
else {
me - > wait_data = ( void * ) m ;
2010-11-26 14:21:48 +01:00
}
2010-09-22 15:10:42 +02:00
2010-11-26 14:21:48 +01:00
queue_node_t * node = queue_remove_head ( & ( me - > msg_waiters ) ) ;
2010-09-22 15:10:42 +02:00
2013-06-24 22:37:35 +02:00
if ( node = = NULL ) {
2013-10-27 08:37:18 +01:00
DEBUG ( " _msg_receive: %s: _msg_receive(): No thread in waiting list. \n " , active_thread - > name ) ;
2013-06-20 18:18:29 +02:00
2013-12-02 16:56:43 +01:00
if ( queue_index < 0 ) {
2013-10-27 08:37:18 +01:00
DEBUG ( " _msg_receive(): %s: No msg in queue. Going blocked. \n " , active_thread - > name ) ;
2013-12-04 20:36:21 +01:00
sched_set_status ( me , STATUS_RECEIVE_BLOCKED ) ;
2010-09-22 15:10:42 +02:00
2010-11-26 14:21:48 +01:00
eINT ( ) ;
thread_yield ( ) ;
2010-09-22 15:10:42 +02:00
2010-11-26 14:21:48 +01:00
/* sender copied message */
}
2013-06-20 18:18:29 +02:00
2010-09-22 15:10:42 +02:00
return 1 ;
2013-06-20 18:18:29 +02:00
}
else {
2013-10-27 08:37:18 +01:00
DEBUG ( " _msg_receive: %s: _msg_receive(): Waking up waiting thread. \n " , active_thread - > name ) ;
2013-06-20 18:18:29 +02:00
tcb_t * sender = ( tcb_t * ) node - > data ;
2010-11-26 14:21:48 +01:00
2013-12-02 16:56:43 +01:00
if ( queue_index > = 0 ) {
2013-12-04 20:36:21 +01:00
/* We've already got a message from the queue. As there is a
2010-11-26 14:21:48 +01:00
* waiter , take it ' s message into the just freed queue space .
*/
m = & ( me - > msg_array [ cib_put ( & ( me - > msg_queue ) ) ] ) ;
}
2010-09-22 15:10:42 +02:00
/* copy msg */
2013-06-20 18:18:29 +02:00
msg_t * sender_msg = ( msg_t * ) sender - > wait_data ;
2010-09-22 15:10:42 +02:00
* m = * sender_msg ;
/* remove sender from queue */
2014-01-25 15:42:13 +01:00
if ( sender - > status ! = STATUS_REPLY_BLOCKED ) {
sender - > wait_data = NULL ;
sched_set_status ( sender , STATUS_PENDING ) ;
}
2010-09-22 15:10:42 +02:00
eINT ( ) ;
return 1 ;
}
}
2010-11-26 14:21:48 +01:00
2013-06-20 18:18:29 +02:00
int msg_init_queue ( msg_t * array , int num )
{
2013-10-28 12:54:16 +01:00
/* check if num is a power of two by comparing to its complement */
2013-06-24 22:37:35 +02:00
if ( num & & ( num & ( num - 1 ) ) = = 0 ) {
2013-06-20 18:18:29 +02:00
tcb_t * me = ( tcb_t * ) active_thread ;
2010-11-26 14:21:48 +01:00
me - > msg_array = array ;
cib_init ( & ( me - > msg_queue ) , num ) ;
return 0 ;
2013-06-20 18:18:29 +02:00
}
2010-11-26 14:21:48 +01:00
return - 1 ;
}