freeze could work:
<Other protected methods of off_IOBank. >+= (<-U) [<-D->]
// These are for freeze:
// Freeze dynamic resource state at curbuf in buf with avail bytes.
virtual err_t freeze_state(char *buf, char *&curbuf, size_t &avail,
char *&curto, size_t &toavail,
const off_prtl_id_t &frozen_domain);
// Copy static resource state in curbuf with toavail bytes.
virtual err_t copy_state(char *&curto, size_t &toavail) const;
as well as these others to support melt:
<Other protected methods of off_IOBank. >+= (<-U) [<-D->]
// These are for melt:
// Does resource cleanup. No external resource should be used after
// return.
virtual err_t cleanup(void);
// Restores the static state from a user supplied buffer.
virtual err_t restore_state(char *&buf, size_t &bsize);
// Restores dynamic resource state.
virtual err_t melt_state(char *&buf, size_t &bsize, char *&from, size_t &size,
const off_prtl_id_t &melted_domain);
The most simple are cleanup and copy_state.
<off_IOBank::cleanup implementation. >= (U->)
// Does resource cleanup. No external resource should be used after
// return.
err_t off_IOBank::cleanup(void)
{
assert(valid() && io_name && io_url);
delete[] io_name;
delete[] io_url;
return EOK;
}
<off_IOBank::copy_state implementation. >= (U->)
// Copy static resource state in curbuf with toavail bytes.
err_t off_IOBank::copy_state(char *&curto, size_t &toavail) const
{
assert(valid());
if (curto){
if (toavail<sizeof(*this))
return ENOSPC;
*(off_IOBank*)curto = *this;
assert(((off_IOBank*)curto)->valid());
curto += sizeof(*this);
toavail-=sizeof(*this);
}
return EOK;
}
The counterpart, restore_state, uses a copy operator tailored not to
copy those members which must remain unaltered (io_attrs).
<Other public methods of off_IOBank. >+= (<-U) [<-D->]
// Copy IO bank contents.
const off_IOBank &operator=(const off_IOBank &other);
It also uses can_melt to know if the frozen IO
bank can be melted on this one.
<Other protected methods of off_IOBank. >+= (<-U) [<-D]
// Is the other bank meltable at this one?
boolean_t can_melt(const off_IOBank *other) const;
<off_IOBank::restore_state implementation. >= (U->)
// Restores the static state from a user supplied buffer.
err_t off_IOBank::restore_state(char *&buf, size_t &bsize)
{
off_IOBank *other=(off_IOBank*)buf;
assert(valid());
if (buf){
if (bsize < sizeof(*this) || !can_melt(other)){
return EINVAL;
}
assert(other->valid());
*this=*other;
buf+=sizeof(*this);
bsize-=sizeof(*this);
}
return EOK;
}
<off_IOBank::operator= implementation. >= (U->)
// Copy IO bank contents.
const off_IOBank &off_IOBank::operator=(const off_IOBank &other)
{
*(off_HWCompResource*)this = *(off_HWCompResource*)&other;
assert(valid() && other.valid());
io_alloc = other.io_alloc;
io_url=other.io_url;
io_name=other.io_name;
io_mdep=other.io_mdep;
return *this;
}
NOTE: XXX freeze sparse allocator.
The frozen IO bank can be melted only if IO addresses contained in the frozen bank are valid for us. Otherwise a ``bigger'' IO bank might be needed. Besides, we should check that we do not loose IO features.
In any case, it only make sense to melt IO banks on the same hardware they were frozen at because the device drivers using their ports will be unable to operate otherwise (they can be melted on different nodes, though).
<off_IOBank::can_melt implementation. >= (U->)
// Is the other IO meltable at this one?
boolean_t off_IOBank::can_melt(const off_IOBank *other) const
{
// NB: Perhaps we should relax and allow `degraded' melts
// where some features are missing. XXX
// Besides, only addresses for allocated ports need to be
// taken into account, not every address.
assert(valid() && other && other->valid());
return ( ! ((other->is_usrio() && !is_usrio()) ||
(other->is_iomapable() && !is_iomapable()) )
&& (other->get_first() >= get_first() &&
other->get_last() <= get_last() &&
other->get_mat() >= get_mat() &&
other->get_iosize(0) == get_iosize(0)));
}
To freeze (or melt) the state of an IO bank we must freeze (or melt)
dynamic members of the bank and also the bitmap allocator being used.
Only the allocator itself is affected, IO port \emph{must}, and will,
remain melted and operational--otherwise it would be not feasible to
transfer the frozen state to a different node. That means that every
IO service (but for allocation and deallocation) is still available.
Applications can keep on running while the IO bank is being
transferred, as it happened with memory banks. The application issuing
the freeze is expected to eventually freeze its ports too (even
when frozen, IO ports will remain operational).
<off_IOBank::freeze_state implementation. >= (U->)
// Freeze dynamic resource state at curbuf in buf with avail bytes.
err_t off_IOBank::freeze_state(char *buf, char *&curbuf, size_t &avail,
char *&curto, size_t &toavail,
const off_prtl_id_t &frozen_domain)
{
(void)curto; (void)toavail;
assert(valid() && buf && curbuf);
set_domain(frozen_domain);
if (!::freeze(io_name,buf,curbuf,avail) ||
!::freeze(io_url,buf,curbuf,avail))
return ENOSPC;
return EOK;
}
<Off IO bank implementation dependencies. >+= (U->) [<-D->] #include <klib/freeze.h> // for ::freeze, ::melt et al.
<off_IOBank::melt_state implementation. >= (U->)
// Restores dynamic resource state.
err_t off_IOBank::melt_state(char *&buf, size_t &bsize,
char *&from, size_t &size,
const off_prtl_id_t &melted_domain)
{
assert(valid() && buf);
(void)from; (void)size;
io_name=::melt(io_name,buf,bsize);
io_url=::melt(io_url,buf,bsize);
set_domain(melted_domain);
return EOK;
}
\subsubsection{Freezing IO ports}
IO ports can also be frozen. We need to implement only these methods:
<Other protected methods of off_IOPort. >+= (<-U) [<-D]
// Copy static resource state in curbuf with toavail bytes.
virtual err_t copy_state(char *&curto, size_t &toavail) const;
// Restores the static state from a user supplied buffer.
virtual err_t restore_state(char *&buf, size_t &bsize);
// Restores dynamic resource state.
<off_IOPort::copy_state implementation. >= (U->)
// Copy static resource state in curbuf with toavail bytes.
err_t off_IOPort::copy_state(char *&curto, size_t &toavail) const
{
assert(valid());
if (curto){
if (toavail<sizeof(*this))
return ENOSPC;
assert(((off_IOPort*)curto)->valid());
*(off_IOPort*)curto = *this;
curto += sizeof(*this);
toavail-=sizeof(*this);
}
return EOK;
}
Note how in this one we take care that io_bank is not affected by
the state restore.
<off_IOPort::restore_state implementation. >= (U->)
// Restores the static state from a user supplied buffer.
err_t off_IOPort::restore_state(char *&buf, size_t &bsize)
{
off_IOPort *other=(off_IOPort*)buf;
assert(valid());
if (buf){
off_IOBank *bank=io_bank;
if (bsize < sizeof(*this)){
return EINVAL;
}
assert(other->valid());
*this=*other;
io_bank=bank;
buf+=sizeof(*this);
bsize-=sizeof(*this);
}
return EOK;
}
To dump an IO bank we use this operator.
<Other public methods of off_IOBank. >+= (<-U) [<-D]
// Dumps iobank state.
friend OStr &operator<<(OStr &s, off_IOBank &io);
<off_IOBank::operator<< implementation. >= (U->)
// Dumps iobank state.
OStr &operator<<(OStr &s, off_IOBank &io)
{
s << *(off_HWCompResource*)&io;
s << "name=" << io.nameof() << " url=" << io.get_url() << nl;
s << "first=" << fmt("%08x",io.get_first()) <<
"last=" << fmt("%08x",io.get_last()) <<
"%d " << io.get_nports() << nl;
for (vm_offset_t p=io.get_first(); p < io.get_last(); p++)
if ((io+p)->get_domain()!=OFF_PRTL_NULL)
s << fmt("%05x ",p) << (io+p)->get_domain() << nl;
return s;
}
<Off IO bank implementation dependencies. >+= (U->) [<-D] #include <klib/str.h> // for OStr et al.
There is no IO port specific stuff to be dumped, thus we rely on the
HWResUnit ``<<'' operator to dump IO ports.