aboutsummaryrefslogblamecommitdiffstats
path: root/bus.h
blob: 707c9e48afc7053fda8366cc99dab401da912225 (plain) (tree)
1
2
3
4
5
6
7
8
9
                                                         



             


                        
                      
                 


 







                                          












                                                 
                   



                                                
                   
 


                      
                   
 





                                                 





















                                                           
                                        











                                           


                                                          

                                                     

                       
 



        


                   






                                                                              
   

                                                           






                                           

                                              
 





                                          

                                                            

                                            

                                                                      






                                          

                                              
 

   
                               



                                                                    


                                                                

                                              

                                                                      












                                                                        

                                                                                     
 



                                                       


















                                                                                     
   

                                                                            



                                                       























                                                                                        
   
                                                                            
                                                                        
                                                               

 







                                                    

                                          
   

                                                                      








                                                             

                                                                      








                                                         



                                                                                 
   

                                                                      















                                                                        

                                                                         

 









                                                                                

                                                                      











                                                                                  

                                                                      

 


      
/* See LICENSE file for copyright and license details. */
#ifndef BUS_H
#define BUS_H


#ifndef _DEFAULT_SOURCE
# define _DEFAULT_SOURCE
#endif
#include <sys/types.h>
#include <time.h>



#if defined(__GNUC__)
# define BUS_COMPILER_GCC(X)  X
#else
# define BUS_COMPILER_GCC(X)  /* ignore */
#endif



/**
 * Open the bus for reading only
 */
#define BUS_RDONLY  1

/**
 * Open the bus for writing only
 */
#define BUS_WRONLY  0

/**
 * Open the bus for both reading and writing only
 */
#define BUS_RDWR  0

/**
 * Fail to create bus if its file already exists
 */
#define BUS_EXCL  2

/**
 * Fail if interrupted
 */
#define BUS_INTR  4

/**
 * Function shall fail with errno set to `EAGAIN`
 * if the it would block and this flag is used
 */
#define BUS_NOWAIT  1



/**
 * The number of bytes in storeable in the shared memory,
 * note that this includes the NUL-termination.
 * This means that message can be at most one byte smaller.
 */
#define BUS_MEMORY_SIZE  2048



/**
 * Bus information
 */
typedef struct bus
{
	/**
	 * The key for the semaphore array
	 */
	key_t key_sem;

	/**
	 * The key for the shared memory
	 */
	key_t key_shm;

	/**
	 * The ID of the semaphore array
	 */
	int sem_id;

	/**
	 * The address of the shared memory
	 */
	char *message;

	/**
	 * Non-zero if and only if `bus_poll` has not been
	 * called since the last `bus_poll_start`, or
	 * if `bus_poll` failed during reading
	 */
	int first_poll;

} bus_t;



/**
 * Create a new bus
 * 
 * @param   file      The pathname of the bus, `NULL` to create a random one
 * @param   flags     `BUS_EXCL` (if `file` is not `NULL`) to fail if the file
 *                    already exists, otherwise if the file exists, nothing
 *                    will happen;
 *                    `BUS_INTR` to fail if interrupted
 * @param   out_file  Output parameter for the pathname of the bus
 * @return            0 on success, -1 on error
 */
BUS_COMPILER_GCC(__attribute__((__warn_unused_result__)))
int bus_create(const char *restrict, int, char **restrict);

/**
 * Remove a bus
 * 
 * @param   file  The pathname of the bus
 * @return        0 on success, -1 on error
 */
BUS_COMPILER_GCC(__attribute__((__nonnull__)))
int bus_unlink(const char *);


/**
 * Open an existing bus
 * 
 * @param   bus    Bus information to fill
 * @param   file   The filename of the bus
 * @param   flags  `BUS_RDONLY`, `BUS_WRONLY` or `BUS_RDWR`,
 *                 the value must not be negative
 * @return         0 on success, -1 on error
 */
BUS_COMPILER_GCC(__attribute__((__nonnull__, __warn_unused_result__)))
int bus_open(bus_t *restrict, const char *restrict, int);

/**
 * Close a bus
 * 
 * @param   bus  Bus information
 * @return       0 on success, -1 on error
 */
BUS_COMPILER_GCC(__attribute__((__nonnull__)))
int bus_close(bus_t *);


/**
 * Broadcast a message on a bus
 * 
 * @param   bus      Bus information
 * @param   message  The message to write, may not be longer than
 *                   `BUS_MEMORY_SIZE` including the NUL-termination
 * @param   flags    `BUS_NOWAIT` if this function shall fail if
 *                   another process is currently running this
 *                   procedure
 * @return           0 on success, -1 on error
 */
BUS_COMPILER_GCC(__attribute__((__nonnull__, __warn_unused_result__)))
int bus_write(const bus_t *, const char *, int);

/**
 * Broadcast a message on a bus
 * 
 * @param   bus      Bus information
 * @param   message  The message to write, may not be longer than
 *                   `BUS_MEMORY_SIZE` including the NUL-termination
 * @param   timeout  The time the operation shall fail with errno set
 *                   to `EAGAIN` if not completed
 * @param   clockid  The ID of the clock the `timeout` is measured with,
 *                   it most be a predictable clock
 * @return           0 on success, -1 on error
 */
BUS_COMPILER_GCC(__attribute__((__nonnull__(1, 2), __warn_unused_result__)))
int bus_write_timed(const bus_t *, const char *, const struct timespec *, clockid_t);


/**
 * Listen (in a loop, forever) for new message on a bus
 * 
 * @param   bus                     Bus information
 * @param   callback                Function to call when a message is received, the
 *            (message, user_data)  input parameters will be the read message and
 *                                  `user_data` from `bus_read`'s parameter with the
 *                                  same name. The message must have been parsed or
 *                                  copied when `callback` returns as it may be over
 *                                  overridden after that time. `callback` should
 *                                  return either of the the values:
 *                                    *  0:  stop listening
 *                                    *  1:  continue listening
 *                                    * -1:  an error has occurred
 *                                  However, the function [`bus_read`] will invoke
 *                                  `callback` with `message` set to `NULL`one time
 *                                  directly after it has started listening on the
 *                                  bus. This is to the the program now it can safely
 *                                  continue with any action that requires that the
 *                                  programs is listening on the bus.
 * @param   user_data               Parameter passed to `callback`
 * @return                          0 on success, -1 on error
 */
BUS_COMPILER_GCC(__attribute__((__nonnull__(1, 2), __warn_unused_result__)))
int bus_read(const bus_t *restrict, int (*)(const char *, void *), void *);

/**
 * Listen (in a loop, forever) for new message on a bus
 * 
 * @param   bus                     Bus information
 * @param   callback                Function to call when a message is received, the
 *            (message, user_data)  input parameters will be the read message and
 *                                  `user_data` from `bus_read`'s parameter with the
 *                                  same name. The message must have been parsed or
 *                                  copied when `callback` returns as it may be over
 *                                  overridden after that time. `callback` should
 *                                  return either of the the values:
 *                                    *  0:  stop listening
 *                                    *  1:  continue listening
 *                                    * -1:  an error has occurred
 *                                  However, the function [`bus_read`] will invoke
 *                                  `callback` with `message` set to `NULL`one time
 *                                  directly after it has started listening on the
 *                                  bus. This is to the the program now it can safely
 *                                  continue with any action that requires that the
 *                                  programs is listening on the bus.
 * @param   user_data               Parameter passed to `callback`
 * @param   timeout                 The time the operation shall fail with errno set
 *                                  to `EAGAIN` if not completed, note that the callback
 *                                  function may or may not have been called
 * @param   clockid                 The ID of the clock the `timeout` is measured with,
 *                                  it most be a predictable clock
 * @return                          0 on success, -1 on error
 */
BUS_COMPILER_GCC(__attribute__((__nonnull__(1, 2), __warn_unused_result__)))
int bus_read_timed(const bus_t *restrict, int (*)(const char *, void *),
                   void *, const struct timespec *, clockid_t);


/**
 * Announce that the thread is listening on the bus.
 * This is required so the will does not miss any
 * messages due to race conditions. Additionally,
 * not calling this function will cause the bus the
 * misbehave, is `bus_poll` is written to expect
 * this function to have been called.
 * 
 * @param   bus  Bus information
 * @return       0 on success, -1 on error
 */
BUS_COMPILER_GCC(__attribute__((__nonnull__, __warn_unused_result__)))
int bus_poll_start(bus_t *);

/**
 * Announce that the thread has stopped listening on the bus.
 * This is required so that the thread does not cause others
 * to wait indefinitely.
 * 
 * @param   bus  Bus information
 * @return       0 on success, -1 on error
 */
BUS_COMPILER_GCC(__attribute__((__nonnull__, __warn_unused_result__)))
int bus_poll_stop(const bus_t *);

/**
 * Wait for a message to be broadcasted on the bus.
 * The caller should make a copy of the received message,
 * without freeing the original copy, and parse it in a
 * separate thread. When the new thread has started be
 * started, the caller of this function should then
 * either call `bus_poll` again or `bus_poll_stop`.
 * 
 * @param   bus    Bus information
 * @param   flags  `BUS_NOWAIT` if the bus should fail and set `errno` to
 *                 `EAGAIN` if there isn't already a message available on the bus
 * @return         The received message, `NULL` on error
 */
BUS_COMPILER_GCC(__attribute__((__nonnull__, __warn_unused_result__)))
const char *bus_poll(bus_t *, int);

/**
 * Wait for a message to be broadcasted on the bus.
 * The caller should make a copy of the received message,
 * without freeing the original copy, and parse it in a
 * separate thread. When the new thread has started be
 * started, the caller of this function should then
 * either call `bus_poll_timed` again or `bus_poll_stop`.
 * 
 * @param   bus      Bus information
 * @param   timeout  The time the operation shall fail with errno set
 *                   to `EAGAIN` if not completed
 * @param   clockid  The ID of the clock the `timeout` is measured with,
 *                   it most be a predictable clock
 * @return           The received message, `NULL` on error
 */
BUS_COMPILER_GCC(__attribute__((__nonnull__(1), __warn_unused_result__)))
const char *bus_poll_timed(bus_t *, const struct timespec *, clockid_t);


/**
 * Change the ownership of a bus
 * 
 * `stat(2)` can be used of the bus's associated file to get the bus's ownership
 * 
 * @param   file   The pathname of the bus
 * @param   owner  The user ID of the bus's new owner
 * @param   group  The group ID of the bus's new group
 * @return         0 on success, -1 on error
 */
BUS_COMPILER_GCC(__attribute__((__nonnull__, __warn_unused_result__)))
int bus_chown(const char *, uid_t, gid_t);

/**
 * Change the permissions for a bus
 * 
 * `stat(2)` can be used of the bus's associated file to get the bus's permissions
 * 
 * @param   file  The pathname of the bus
 * @param   mode  The permissions of the bus, any permission for a user implies
 *                full permissions for that user, except only the owner may
 *                edit the bus's associated file
 * @return        0 on success, -1 on error
 */
BUS_COMPILER_GCC(__attribute__((__nonnull__, __warn_unused_result__)))
int bus_chmod(const char *, mode_t);



#endif