The following callbacks are concerned: - state_save - state_isvalid Change-Id: I75f71fe162ccd8b23b18cae15f844b79b290a8c1
		
			
				
	
	
		
			371 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			371 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include "syslib.h"
 | 
						|
#include <assert.h>
 | 
						|
#include <minix/sysutil.h>
 | 
						|
 | 
						|
/* SEF Live update variables. */
 | 
						|
static int sef_lu_state;
 | 
						|
static int sef_lu_flags;
 | 
						|
 | 
						|
extern __attribute__((weak)) int st_do_state_cleanup(void);
 | 
						|
 | 
						|
/* SEF Live update callbacks. */
 | 
						|
static struct sef_cbs {
 | 
						|
    sef_cb_lu_prepare_t                 sef_cb_lu_prepare;
 | 
						|
    sef_cb_lu_state_isvalid_t           sef_cb_lu_state_isvalid;
 | 
						|
    sef_cb_lu_state_changed_t           sef_cb_lu_state_changed;
 | 
						|
    sef_cb_lu_state_dump_t              sef_cb_lu_state_dump;
 | 
						|
    sef_cb_lu_state_save_t              sef_cb_lu_state_save;
 | 
						|
    sef_cb_lu_response_t                sef_cb_lu_response;
 | 
						|
} sef_cbs = {
 | 
						|
    SEF_CB_LU_PREPARE_DEFAULT,
 | 
						|
    SEF_CB_LU_STATE_ISVALID_DEFAULT,
 | 
						|
    SEF_CB_LU_STATE_CHANGED_DEFAULT,
 | 
						|
    SEF_CB_LU_STATE_DUMP_DEFAULT,
 | 
						|
    SEF_CB_LU_STATE_SAVE_DEFAULT,
 | 
						|
    SEF_CB_LU_RESPONSE_DEFAULT
 | 
						|
};
 | 
						|
 | 
						|
/* SEF Live update prototypes for sef_receive(). */
 | 
						|
void do_sef_lu_before_receive(void);
 | 
						|
int do_sef_lu_request(message *m_ptr);
 | 
						|
 | 
						|
/* SEF Live update helpers. */
 | 
						|
static void sef_lu_ready(int result);
 | 
						|
 | 
						|
/* Debug. */
 | 
						|
EXTERN char* sef_debug_header(void);
 | 
						|
static int sef_lu_debug_cycle = 0;
 | 
						|
 | 
						|
/* Information about SELF. */
 | 
						|
EXTERN endpoint_t sef_self_endpoint;
 | 
						|
EXTERN int sef_self_first_receive_done;
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *                         do_sef_lu_before_receive             	     *
 | 
						|
 *===========================================================================*/
 | 
						|
void do_sef_lu_before_receive(void)
 | 
						|
{
 | 
						|
/* Handle SEF Live update before receive events. */
 | 
						|
  int r;
 | 
						|
 | 
						|
  /* Initialize on first receive. */
 | 
						|
  if(!sef_self_first_receive_done) {
 | 
						|
      sef_lu_state = SEF_LU_STATE_NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Nothing to do if we are not preparing for a live update. */
 | 
						|
  if(sef_lu_state == SEF_LU_STATE_NULL) {
 | 
						|
      return;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Debug. */
 | 
						|
#if SEF_LU_DEBUG
 | 
						|
  sef_lu_debug_cycle++;
 | 
						|
  sef_lu_debug_begin();
 | 
						|
  sef_lu_dprint("%s, cycle=%d. Dumping state variables:\n",
 | 
						|
      sef_debug_header(), sef_lu_debug_cycle);
 | 
						|
  sef_cbs.sef_cb_lu_state_dump(sef_lu_state);
 | 
						|
  sef_lu_debug_end();
 | 
						|
#endif
 | 
						|
 | 
						|
  /* Let the callback code handle the event.
 | 
						|
   * For SEF_LU_STATE_WORK_FREE, we're always ready, tell immediately.
 | 
						|
   */
 | 
						|
  r = OK;
 | 
						|
  if(sef_lu_state != SEF_LU_STATE_WORK_FREE) {
 | 
						|
      r = sef_cbs.sef_cb_lu_prepare(sef_lu_state);
 | 
						|
  }
 | 
						|
  if(r == OK) {
 | 
						|
      sef_lu_ready(OK);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *                               do_sef_lu_request              	     *
 | 
						|
 *===========================================================================*/
 | 
						|
int do_sef_lu_request(message *m_ptr)
 | 
						|
{
 | 
						|
/* Handle a SEF Live update request. */
 | 
						|
  int state, old_state, flags, is_valid_state;
 | 
						|
 | 
						|
  sef_lu_debug_cycle = 0;
 | 
						|
  old_state = sef_lu_state;
 | 
						|
  state = m_ptr->m_rs_update.state;
 | 
						|
  flags = m_ptr->m_rs_update.flags;
 | 
						|
 | 
						|
  /* Deal with prepare cancel requests first. */
 | 
						|
  is_valid_state = (state == SEF_LU_STATE_NULL);
 | 
						|
 | 
						|
  /* Otherwise only accept live update requests with a valid state. */
 | 
						|
  is_valid_state = SEF_LU_ALWAYS_ALLOW_DEBUG_STATES && SEF_LU_STATE_IS_DEBUG(state);
 | 
						|
  is_valid_state = is_valid_state || sef_cbs.sef_cb_lu_state_isvalid(state, flags);
 | 
						|
  if(!is_valid_state) {
 | 
						|
      if(sef_cbs.sef_cb_lu_state_isvalid == SEF_CB_LU_STATE_ISVALID_DEFAULT) {
 | 
						|
          sef_lu_ready(ENOSYS);
 | 
						|
      }
 | 
						|
      else {
 | 
						|
          sef_lu_ready(EINVAL);
 | 
						|
      }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
      /* Set the new live update state. */
 | 
						|
      sef_lu_state = state;
 | 
						|
 | 
						|
      /* If the live update state changed, let the callback code
 | 
						|
       * handle the rest.
 | 
						|
       */
 | 
						|
      if(old_state != sef_lu_state) {
 | 
						|
          sef_cbs.sef_cb_lu_state_changed(old_state, sef_lu_state);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /* Return OK not to let anybody else intercept the request. */
 | 
						|
  return(OK);
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				  sef_lu_ready				     *
 | 
						|
 *===========================================================================*/
 | 
						|
static void sef_lu_ready(int result)
 | 
						|
{
 | 
						|
  message m;
 | 
						|
  int old_state, r=EINVAL;
 | 
						|
 | 
						|
#if SEF_LU_DEBUG
 | 
						|
  sef_lu_debug_begin();
 | 
						|
  sef_lu_dprint("%s, cycle=%d. Ready to update with result: %d%s\n",
 | 
						|
      sef_debug_header(), sef_lu_debug_cycle,
 | 
						|
      result, (result == OK ? "(OK)" : ""));
 | 
						|
  sef_lu_debug_end();
 | 
						|
#endif
 | 
						|
 | 
						|
  /* If result is OK, let the callback code cleanup and save
 | 
						|
   * any state that must be carried over to the new version.
 | 
						|
   */
 | 
						|
  if(result == OK) {
 | 
						|
      /* st_do_state_cleanup is a weak symbol. It is only defined if
 | 
						|
       * we are linked against magic */
 | 
						|
      if (st_do_state_cleanup)
 | 
						|
          r = st_do_state_cleanup();
 | 
						|
      if(r == OK) {
 | 
						|
          r = sef_cbs.sef_cb_lu_state_save(sef_lu_state, sef_lu_flags);
 | 
						|
      }
 | 
						|
      if(r != OK) {
 | 
						|
          /* Abort update in case of error. */
 | 
						|
          result = r;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /* Let the callback code produce a live update response and block.
 | 
						|
   * We should get beyond this point only if either result is an error or
 | 
						|
   * something else goes wrong in the callback code.
 | 
						|
   */
 | 
						|
  m.m_source = sef_self_endpoint;
 | 
						|
  m.m_type = RS_LU_PREPARE;
 | 
						|
  m.m_rs_update.state = sef_lu_state;
 | 
						|
  m.m_rs_update.result = result;
 | 
						|
  r = sef_cbs.sef_cb_lu_response(&m);
 | 
						|
 | 
						|
#if SEF_LU_DEBUG
 | 
						|
  sef_lu_debug_begin();
 | 
						|
  sef_lu_dprint("%s, cycle=%d. The %s aborted the update with result %d!\n",
 | 
						|
      sef_debug_header(), sef_lu_debug_cycle,
 | 
						|
      (result == OK ? "server" : "client"),
 | 
						|
      (result == OK ? r : result)); /* EINTR if update was canceled. */
 | 
						|
  sef_lu_debug_end();
 | 
						|
#endif
 | 
						|
 | 
						|
  /* Something went wrong. Update was aborted and we didn't get updated.
 | 
						|
   * Restore things back to normal and continue executing.
 | 
						|
   */
 | 
						|
  old_state = sef_lu_state;
 | 
						|
  sef_lu_state = SEF_LU_STATE_NULL;
 | 
						|
  if(old_state != sef_lu_state) {
 | 
						|
      sef_cbs.sef_cb_lu_state_changed(old_state, sef_lu_state);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *                            sef_setcb_lu_prepare                           *
 | 
						|
 *===========================================================================*/
 | 
						|
void sef_setcb_lu_prepare(sef_cb_lu_prepare_t cb)
 | 
						|
{
 | 
						|
  assert(cb != NULL);
 | 
						|
  sef_cbs.sef_cb_lu_prepare = cb;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *                         sef_setcb_lu_state_isvalid                        *
 | 
						|
 *===========================================================================*/
 | 
						|
void sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_t cb)
 | 
						|
{
 | 
						|
  assert(cb != NULL);
 | 
						|
  sef_cbs.sef_cb_lu_state_isvalid = cb;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *                         sef_setcb_lu_state_changed                        *
 | 
						|
 *===========================================================================*/
 | 
						|
void sef_setcb_lu_state_changed(sef_cb_lu_state_changed_t cb)
 | 
						|
{
 | 
						|
  assert(cb != NULL);
 | 
						|
  sef_cbs.sef_cb_lu_state_changed = cb;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *                          sef_setcb_lu_state_dump                          *
 | 
						|
 *===========================================================================*/
 | 
						|
void sef_setcb_lu_state_dump(sef_cb_lu_state_dump_t cb)
 | 
						|
{
 | 
						|
  assert(cb != NULL);
 | 
						|
  sef_cbs.sef_cb_lu_state_dump = cb;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *                          sef_setcb_lu_state_save                           *
 | 
						|
 *===========================================================================*/
 | 
						|
void sef_setcb_lu_state_save(sef_cb_lu_state_save_t cb)
 | 
						|
{
 | 
						|
  assert(cb != NULL);
 | 
						|
  sef_cbs.sef_cb_lu_state_save = cb;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *                          sef_setcb_lu_response                            *
 | 
						|
 *===========================================================================*/
 | 
						|
void sef_setcb_lu_response(sef_cb_lu_response_t cb)
 | 
						|
{
 | 
						|
  assert(cb != NULL);
 | 
						|
  sef_cbs.sef_cb_lu_response = cb;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *      	            sef_cb_lu_prepare_null 	 	             *
 | 
						|
 *===========================================================================*/
 | 
						|
int sef_cb_lu_prepare_null(int UNUSED(state))
 | 
						|
{
 | 
						|
  return ENOTREADY;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *      	         sef_cb_lu_state_isvalid_null		             *
 | 
						|
 *===========================================================================*/
 | 
						|
int sef_cb_lu_state_isvalid_null(int UNUSED(state), int UNUSED(flags))
 | 
						|
{
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *                       sef_cb_lu_state_changed_null        		     *
 | 
						|
 *===========================================================================*/
 | 
						|
void sef_cb_lu_state_changed_null(int UNUSED(old_state),
 | 
						|
   int UNUSED(state))
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *                       sef_cb_lu_state_dump_null        		     *
 | 
						|
 *===========================================================================*/
 | 
						|
void sef_cb_lu_state_dump_null(int UNUSED(state))
 | 
						|
{
 | 
						|
  sef_lu_dprint("NULL\n");
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *                       sef_cb_lu_state_save_null        		     *
 | 
						|
 *===========================================================================*/
 | 
						|
int sef_cb_lu_state_save_null(int UNUSED(result), int UNUSED(flags))
 | 
						|
{
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *                       sef_cb_lu_response_null        		     *
 | 
						|
 *===========================================================================*/
 | 
						|
int sef_cb_lu_response_null(message * UNUSED(m_ptr))
 | 
						|
{
 | 
						|
  return ENOSYS;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *      	       sef_cb_lu_prepare_always_ready	                     *
 | 
						|
 *===========================================================================*/
 | 
						|
int sef_cb_lu_prepare_always_ready(int UNUSED(state))
 | 
						|
{
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *      	       sef_cb_lu_prepare_never_ready	                     *
 | 
						|
 *===========================================================================*/
 | 
						|
int sef_cb_lu_prepare_never_ready(int UNUSED(state))
 | 
						|
{
 | 
						|
#if SEF_LU_DEBUG
 | 
						|
  sef_lu_debug_begin();
 | 
						|
  sef_lu_dprint("%s, cycle=%d. Simulating a service never ready to update...\n",
 | 
						|
      sef_debug_header(), sef_lu_debug_cycle);
 | 
						|
  sef_lu_debug_end();
 | 
						|
#endif
 | 
						|
 | 
						|
  return ENOTREADY;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *      	         sef_cb_lu_prepare_crash	                     *
 | 
						|
 *===========================================================================*/
 | 
						|
int sef_cb_lu_prepare_crash(int UNUSED(state))
 | 
						|
{
 | 
						|
  panic("Simulating a crash at update prepare time...");
 | 
						|
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *      	      sef_cb_lu_state_isvalid_standard                       *
 | 
						|
 *===========================================================================*/
 | 
						|
int sef_cb_lu_state_isvalid_standard(int state, int UNUSED(flags))
 | 
						|
{
 | 
						|
  return SEF_LU_STATE_IS_STANDARD(state);
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *      	      sef_cb_lu_state_isvalid_workfree                       *
 | 
						|
 *===========================================================================*/
 | 
						|
int sef_cb_lu_state_isvalid_workfree(int state, int UNUSED(flags))
 | 
						|
{
 | 
						|
  return (state == SEF_LU_STATE_WORK_FREE);
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *      	    sef_cb_lu_state_isvalid_workfree_self                    *
 | 
						|
 *===========================================================================*/
 | 
						|
int sef_cb_lu_state_isvalid_workfree_self(int state, int flags)
 | 
						|
{
 | 
						|
  return (state == SEF_LU_STATE_WORK_FREE) && (flags & (SEF_LU_SELF|SEF_LU_ASR));
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *      	       sef_cb_lu_state_isvalid_generic                       *
 | 
						|
 *===========================================================================*/
 | 
						|
int sef_cb_lu_state_isvalid_generic(int state, int flags)
 | 
						|
{
 | 
						|
  return (state == SEF_LU_STATE_EVAL) || sef_cb_lu_state_isvalid_workfree(state, flags);
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *                       sef_cb_lu_response_rs_reply        		     *
 | 
						|
 *===========================================================================*/
 | 
						|
int sef_cb_lu_response_rs_reply(message *m_ptr)
 | 
						|
{
 | 
						|
  int r;
 | 
						|
 | 
						|
  /* Inform RS that we're ready with the given result. */
 | 
						|
  r = ipc_sendrec(RS_PROC_NR, m_ptr);
 | 
						|
  if ( r != OK) {
 | 
						|
      return r;
 | 
						|
  }
 | 
						|
 | 
						|
  return m_ptr->m_type == RS_LU_PREPARE ? EINTR : m_ptr->m_type;
 | 
						|
}
 | 
						|
 |