errors flounder FLOUNDER_ERR_ {
failure INVALID_STATE "Invalid/corrupt state in binding structure",
failure TX_BUSY "Cannot queue message for transmit: queue is full",
+ failure TX_MSG_SIZE "Trying to send a message which is larger than declared",
failure RX_EMPTY_MSG "Incoming message invalid: empty payload",
failure RX_INVALID_MSGNUM "Incoming message invalid: unknown message code",
failure RX_INVALID_LENGTH "Incoming message has invalid length",
out uint8 startbus,
out uint8 endbus);
- rpc read_irq_table(in string handle,
+ rpc read_irq_table(in String handle[256],
in pci_address addr,
in uint8 bus,
out errval error,
- out string child);
+ out String child[256]);
- rpc set_device_irq(in string handle,
+ rpc set_device_irq(in String handle[2048],
in uint32 irq,
out errval error);
rpc reset(out errval err);
rpc sleep(in uint32 state, out errval err);
- rpc get_handle(in string devid, out uint64 handle, out errval err);
- rpc eval_integer(in uint64 handle, in string path, out uint64 val, out errval err);
+ rpc get_handle(in String devid[2048], out uint64 handle, out errval err);
+ rpc eval_integer(in uint64 handle, in String path[2048], out uint64 val, out errval err);
// Kludge: retrieve frame cap to VBE BIOS;
rpc get_vbe_bios_cap(out errval err, out cap cap, out uint32 size);
rpc vtd_remove_device(in uint32 seg, in uint32 bus, in uint32 dev, in uint32 funct, in cap pml4, out errval err);
rpc vtd_id_dom_add_devices(out errval err);
-
+
// More Kludge; cap retrieval for pci
// We need a designated service to maintain the physical address
// space caps (to avoid sibling errors).
interface ahci_mgmt "AHCI Management Daemon" {
- rpc list(out uint8 port_ids[len]);
- rpc identify(in uint8 port_id, out uint8 identify_data[data_len]);
+ rpc list(out uint8 port_ids[len, 128]);
+ rpc identify(in uint8 port_id, out uint8 identify_data[data_len, 512]);
rpc open(in uint8 port_id, out errval status, out cap controller_mem, out uint64 offset, out uint32 capabilities);
rpc close(in uint8 port_id, out errval status);
*/
interface arrakis "Interface to arrakismon" {
- rpc spawn_arrakis_domain(in string path, in char argvbuf[argvbytes],
- in char envbuf[envbytes], out errval err, out domainid domain_id);
+ rpc spawn_arrakis_domain(in String path[2048], in char argvbuf[argvbytes, 2048],
+ in char envbuf[envbytes, 2048], out errval err, out domainid domain_id);
};
+
interface ata_rw28 "ATA read & write with 28-bit LBA" {
@ata(command=0xC8, dma_arg=buffer, dma_size=read_size, lba=start_lba)
- rpc read_dma(in uint32 read_size, in uint32 start_lba, out uint8 buffer[buffer_size]);
+ rpc read_dma(in uint32 read_size, in uint32 start_lba, out uint8 buffer[buffer_size, 2048]);
@ata(command=0xC8, dma_arg=buffer, dma_size=512, lba=lba)
- rpc read_dma_block(in uint32 lba, out uint8 buffer[buffer_size]);
+ rpc read_dma_block(in uint32 lba, out uint8 buffer[buffer_size, 2048]);
@ata(command=0xCA, dma_arg=buffer, is_write=1, lba=lba)
- rpc write_dma(in uint8 buffer[buffer_size], in uint32 lba, out errval status);
+ rpc write_dma(in uint8 buffer[buffer_size, 2048], in uint32 lba, out errval status);
@ata(command=0xEC, dma_arg=buffer, dma_size=512)
- rpc identify_device(out uint8 buffer[buffer_size]);
+ rpc identify_device(out uint8 buffer[buffer_size, 2048]);
@ata(command=0xE7)
rpc flush_cache(out errval status);
};
+
rpc new_client(out cap bulk);
- rpc get_start(in char key[key_len], out uint64 idx, out bool haveit, out uint64 transid, out uint64 size);
+ rpc get_start(in char key[key_len, 2048], out uint64 idx, out bool haveit, out uint64 transid, out uint64 size);
rpc get_stop(in uint64 transid, in uint64 idx, in uint64 length);
rpc print_stats();
};
+
message fsb_init_msg(uint8 coreid);
message fsb_empty_request();
message fsb_empty_reply();
- message fsb_buffer_request(uint8 buf[size]);
- message fsb_buffer_reply(uint8 buf[size]);
+ message fsb_buffer_request(uint8 buf[size, 2048]);
+ message fsb_buffer_reply(uint8 buf[size, 2048]);
message fsb_payload_request(int word0, int word1, int word2, int word3);
message fsb_payload_reply(int word0, int word1, int word2, int word3);
message shmc_start();
message shmc_done();
};
+
* --------
* The storage server implements a log-structured data store,
* from which data can be read or written in terms of chunks.
- * A chunk is a block of data of a specific size with a
- * unique ID. A client or directory server can read or
+ * A chunk is a block of data of a specific size with a
+ * unique ID. A client or directory server can read or
* write chunks from the storage by passing the ID of the chunk.
*/
rpc ds_create(
in OBJECT_TYPE ob_type,
in OBJECT_ACCESS_PERM ob_perm,
- in string ob_name,
+ in String ob_name[2048],
in uint64 client_id,
out object_key object);
-rpc ds_open(
+rpc ds_open(
in OBJECT_TYPE ob_type,
in OBJECT_ACCESS_PERM ob_perm,
- in string ob_name,
+ in String ob_name[2048],
in uint64 client_id,
out object_key object);
* -----------------------------------------------
* XXX TO DO: make the maintenance of replicated state
* be implicit via a consensus protocol.
- *
+ *
* Name server can broadcast current list of servers
* to all SS and DS servers in the system. This is a
* one-way notification.
*/
-message ss_notify_registered_servers(
- uint64 server);
-message ds_notify_registered_servers(
- uint64 server);
+message ss_notify_registered_servers(uint64 server);
+message ds_notify_registered_servers(uint64 server);
};
+
* tid is a transaction id, used to mark which request a given reply belongs to
*
*/
-
+
/*
rpc move(in poolid poolid,
in uint32 bufferid,
in uint32 tid,
in cap cap,
- in uint8 meta[metasize],
+ in uint8 meta[metasize, 2048],
out error error,
out uint32 tid);
*/
uint32 bufferid,
uint32 tid,
cap cap,
- uint8 meta[metasize]);
+ uint8 meta[metasize, 2048]);
message move_trusted_call(poolid poolid,
uint32 bufferid,
uint32 tid,
- uint8 meta[metasize]);
+ uint8 meta[metasize, 2048]);
message move_response(error error,
in uint32 bufferid,
in uint32 tid,
in cap cap,
- in uint8 meta[metasize],
+ in uint8 meta[metasize, 2048],
out error error,
out uint32 tid);
*/
uint32 bufferid,
uint32 tid,
cap cap,
- uint8 meta[metasize]);
+ uint8 meta[metasize, 2048]);
message copy_trusted_call(poolid poolid,
uint32 bufferid,
uint32 tid,
- uint8 meta[metasize]);
+ uint8 meta[metasize, 2048]);
message copy_response(error error,
in uint32 bufferid,
in uint32 tid,
in cap cap,
- in uint8 meta[metasize],
+ in uint8 meta[metasize, 2048],
out error error,
out uint32 tid);
*/
uint32 bufferid,
uint32 tid,
cap cap,
- uint8 meta[metasize]);
+ uint8 meta[metasize, 2048]);
message pass_trusted_call(poolid poolid,
uint32 bufferid,
uint32 tid,
- uint8 meta[metasize]);
+ uint8 meta[metasize, 2048]);
message pass_response(error error,
uint32 tid);
message release_response(error error,
uint32 tid);
};
+
*/
interface bulkbench "Bulk benchmark Interface" {
- message bulk_init(cap shared_mem);
- message bulk_init_reply();
+ message bulk_init(cap shared_mem);
+ message bulk_init_reply();
- message message_request(uint8 msg[size]);
- message message_reply();
+ message message_request(uint8 msg[size, 2048]);
+ message message_reply();
- message bulk_message_request(uint64 id, uint64 size, uint8 last_fragment);
- message bulk_message_reply(uint64 id, uint8 last_fragment);
+ message bulk_message_request(uint64 id, uint64 size, uint8 last_fragment);
+ message bulk_message_reply(uint64 id, uint8 last_fragment);
};
+
interface dist_event "dist2 Publish/Subscribe Events" {
message identify(uint64 id);
-
- message subscribed_message(uint64 id, string record);
- message watch_event(uint64 id, string record);
-
- message trigger(uint64 id, string record);
+
+ message subscribed_message(uint64 id, String record[2048]);
+ message watch_event(uint64 id, String record[2048]);
+
+ message trigger(uint64 id, String record[2048]);
};
+
// Resource control
message rsrc_join(rsrcid id, coreid coreid);
message rsrc_join_complete(rsrcid id);
- message rsrc_phase_data(rsrcid id, uint32 phase, uint8 data[len]);
+ message rsrc_phase_data(rsrcid id, uint32 phase, uint8 data[len, 2048]);
message rsrc_timer_sync(uint64 timestamp);
message rsrc_timer_sync_reply(errval err);
message multihop_routing_table_response(errval err,
coreid source_coreid,
coreid max_coreid,
- coreid to[len]);
+ coreid to[len, 2048]);
// grow the routing table to a set of desination cores, via a given forwarder
- message multihop_routing_table_grow(coreid forwarder, coreid destinations[len]);
+ message multihop_routing_table_grow(coreid forwarder, coreid destinations[len, 2048]);
// set up a new multihop virtual circuit
message bind_multihop_intermon_request(iref iref, vci sender_vci,
errval err);
message multihop_message(vci vci, uint8 direction, uint8 flags, uint32 ack,
- uint8 payload[size]);
+ uint8 payload[size, 2048]);
message multihop_cap_send(vci vci, uint8 direction, capid capid, errval err,
caprep cap, bool null_cap, coreid owner);
message forward_kcb_rm_request(uint64 kcb_base);
message forward_kcb_rm_response(errval err);
};
+
*/
interface interphi "Interface between host and card side driver" {
-
- rpc domain_lookup(in char name[length],
+
+ rpc domain_lookup(in char name[length, 2048],
out uint64 domid,
out errval msgerr);
-
- rpc domain_wait(in char name[length],
+
+ rpc domain_wait(in char name[length, 2048],
in uint64 state,
out uint64 domid,
out uint64 rstate,
out errval msgerr);
-
- rpc domain_register(in char name[length],
+
+ rpc domain_register(in char name[length, 2048],
in uint64 domid,
out errval msgerr);
-
+
/**
* \
*/
- rpc spawn(in uint8 core,
- in char cmdline[length],
+ rpc spawn(in uint8 core,
+ in char cmdline[length, 2048],
in uint8 flags,
out uint64 domainid,
out errval msgerr);
-
+
/**
- *
+ *
*/
- rpc spawn_with_cap(in uint8 core,
- in char cmdline[length],
+ rpc spawn_with_cap(in uint8 core,
+ in char cmdline[length, 2048],
in uint8 flags,
in uint64 cap_base,
in uint8 cap_size_bits,
out uint64 domainid,
out errval msgerr);
-
+
/**
- *
+ *
*/
- rpc kill(in uint64 domainid,
+ rpc kill(in uint64 domainid,
out errval msgerr);
-
-
+
+
/**
- *
+ *
*/
rpc bootstrap(in uint64 base,
in uint64 offset,
in uint8 xid,
in uint8 is_client,
out errval msgerr);
-
+
rpc chan_open(in uint64 source_did,
in uint64 target_did,
in uint64 usrdata,
/*
* host driver only
*/
-
-
- rpc register(in uint8 id,
+
+
+ rpc register(in uint8 id,
in uint64 local_apt_base,
- in uint64 local_apt_size,
- out errval msgerr,
+ in uint64 local_apt_size,
+ out errval msgerr,
out uint64 other_apt_base,
out uint64 other_apt_size);
-
- rpc bootstrap_remote(in uint64 base,
- in uint8 bits,
- out errval msgerr);
-};
\ No newline at end of file
+
+ rpc bootstrap_remote(in uint64 base,
+ in uint8 bits,
+ out errval msgerr);
+};
message multihop_routing_table_new(coreid max_coreid, coreid nentries);
// Subsequent messages (repeated) which each contain
// a portion of the routing table from a single core
- message multihop_routing_table_set(coreid from, coreid to[len]);
+ message multihop_routing_table_set(coreid from, coreid to[len, 128]);
// Connection set-up between monitor and client
message multihop_bind_client_request(iref iref, vci sender_vci);
// user message
message multihop_message(vci vci, uint8 direction, uint8 flags, uint32 ack,
- uint8 payload[size]);
+ uint8 payload[size, 256]);
// cap transfer
message multihop_cap_send(vci vci, uint8 direction, errval err, cap cap,
rpc get_irq_dest_cap(out cap io, out errval err);
// Resource control
- rpc rsrc_manifest(in cap dispatcher, in string manifest,
+ rpc rsrc_manifest(in cap dispatcher, in String manifest[2048],
out rsrcid id, out errval err);
rpc rsrc_join(in rsrcid id, in cap dispatcher, out errval err);
rpc rsrc_phase(in rsrcid id, in uint32 phase);
//
rpc get_identifier(out uint64 id);
rpc identify(in uint64 id, in binding_type type);
-
-
+
+
//
// Get/Set API
//
/**
* \param query Records to find.
* \param t Additional trigger to watch for future events.
- * \param output Comma separated string of record names or NULL on error.
+ * \param output Comma separated String of record names or NULL on error.
* \param tid Id of registered trigger (0 in case no trigger registered).
* \param error_code Error value of request.
*/
- rpc get_names(in string query, in trigger t, out string output,
+ rpc get_names(in String query[2048], in trigger t, out String output[2048],
out trigger_id tid, out errval error_code);
-
+
/**
* \param query Record to find.
* \param t Additional trigger to watch for future events.
* \param tid Id of registered trigger (0 in case no trigger registered).
* \param error_code Error value of request.
*/
- rpc get(in string query, in trigger t, out string output,
+ rpc get(in String query[2048], in trigger t, out String output[2048],
out trigger_id tid, out errval error_code);
-
+
/**
* \param query Record to set.
* \param mode Set mode (see getset.h).
* \param t Additional trigger to watch for future events.
* \param get Return record if it has been set.
- * \param record In case get is true and no error_code is ok
+ * \param record In case get is true and no error_code is ok
* contains record, otherwise NULL
* \param tid Id of registered trigger (0 in case no trigger registered).
* \param error_code Error value of request
*/
- rpc set(in string query, in uint64 mode, in trigger t, in bool get,
- out string record, out trigger_id tid, out errval error_code);
+ rpc set(in String query[2048], in uint64 mode, in trigger t, in bool get,
+ out String record[2048], out trigger_id tid, out errval error_code);
/**
* Find a record using an ID capability as the key/name of the record.
* \param tid Id of registered trigger (0 in case no trigger registered).
* \param error_code Error value of request.
*/
- rpc get_with_idcap(in cap idcap, in trigger t, out string output,
+ rpc get_with_idcap(in cap idcap, in trigger t, out String output[2048],
out trigger_id tid, out errval error_code);
/**
* \param tid Id of registered trigger (0 in case no trigger registered).
* \param error_code Error value of request
*/
- rpc set_with_idcap(in cap idcap, in string attributes, in uint64 mode,
- in trigger t, in bool get, out string record,
+ rpc set_with_idcap(in cap idcap, in String attributes[2048], in uint64 mode,
+ in trigger t, in bool get, out String record[2048],
out trigger_id tid, out errval error_code);
-
+
/**
* \param query Record(s) to delete.
* \param t Additional trigger to watch for future events.
* \param tid Id of registered trigger (0 in case no trigger registered).
* \param error_code Error value of request
*/
- rpc del(in string query, in trigger t, out trigger_id tid,
+ rpc del(in String query[2048], in trigger t, out trigger_id tid,
out errval error_code);
-
+
/**
* \param query
* \param t Additional trigger to watch for future events.
* \param tid Id of registered trigger (0 in case no trigger registered).
* \param error_code Error value of request.
*/
- rpc exists(in string query, in trigger t, out trigger_id tid,
+ rpc exists(in String query[2048], in trigger t, out trigger_id tid,
out errval error_code);
-
+
/**
* \brief Blocks until a record matching the provided query is registered.
*
* \param record
* \param error_code
*/
- rpc wait_for(in string query, out string record, out errval error_code);
-
+ rpc wait_for(in String query[2048], out String record[2048], out errval error_code);
+
/**
* \brief Used to remove Triggers in case they are not needed anymore.
*
- * Note that non persistent trigger are removed automatically after
+ * Note that non persistent trigger are removed automatically after
* they have fired. For persistent triggers be aware that you might
* still get a notification after the trigger has been removed because
* trigger events are sent over another binding.
* \param error_code Error of operation
*/
rpc remove_trigger(in uint64 id, out errval error_code);
-
+
//
// Publish/Subscribe API
//
-
+
/**
* \param query
* \param client_state Additional state supplied by client.
* \param id Identifier for this subscription supplied by server.
* \param error_code Status of request.
*/
- rpc subscribe(in string query, in uint64 trigger_fn, in uint64 state,
+ rpc subscribe(in String query[2048], in uint64 trigger_fn, in uint64 state,
out uint64 id, out errval error_code);
-
+
/**
* \param id Id for the subscription
* \param error_code Status of request
*/
rpc unsubscribe(in uint64 id, out errval error_code);
-
+
/**
* \param record Message to publish.
* \param error_code Status of request.
*/
- rpc publish(in string record, out errval error_code);
+ rpc publish(in String record[2048], out errval error_code);
//
// Async events (sent by server to client)
//
- message trigger(trigger_id id, uint64 trigger_fn, mode m, string record,
+ message trigger(trigger_id id, uint64 trigger_fn, mode m, String record[2048],
uint64 state);
message subscription(trigger_id id, uint64 trigger_fn, mode m,
- string record, uint64 state);
-
+ String record[2048], uint64 state);
+
//
// Backward compability with chips
//
-
+
// Simple capability storage
- rpc get_cap(in string key, out cap retcap, out errval reterr);
- rpc put_cap(in string key, in cap storecap, out errval reterr);
- rpc remove_cap(in string key, out errval reterr);
+ rpc get_cap(in String key[2048], out cap retcap, out errval reterr);
+ rpc put_cap(in String key[2048], in cap storecap, out errval reterr);
+ rpc remove_cap(in String key[2048], out errval reterr);
};
in uint32 fun,
out errval err,
out uint8 nr_allocated_bars, // Number of bars supported
- out caps_per_bar caps_per_bar);
+ out uint32 caps_per_bar0,
+ out uint32 caps_per_bar1,
+ out uint32 caps_per_bar2,
+ out uint32 caps_per_bar3,
+ out uint32 caps_per_bar4,
+ out uint32 caps_per_bar5);
/* Init legacy IO device */
rpc init_legacy_device(in uint16 iomin,
interface ping_pong "Ping-Pong async example Interface" {
// The following messages are used in the test program
- message rsrc_join_request(uint32 id);
- message rsrc_join_reply();
- message init();
- message ping(uint64 val);
- message pong(uint64 val);
+ message rsrc_join_request(uint32 id);
+ message rsrc_join_reply();
+ message init();
+ message ping(uint64 val);
+ message pong(uint64 val);
message slow_op(uint64 val);
message slow_reply(uint64 val);
- message stop();
-
- rpc testrpc(in uint64 testin, out uint64 testout);
- rpc testrpc2(in uint64 testin, out uint64 testout);
-
- rpc outoforder(in uint64 seq_in,
- out uint64 seq_out,
- in uint64 testin,
- out uint64 testout);
-
- // The following messages are not used in practice, but
- // exercise the THC Flounder back-end
-
- message str0(uint32 arg1, string s);
- message str1(uint32 arg1, string s);
- message str2(uint32 arg1, string s);
- rpc str3(in uint32 arg1, in string s);
- rpc str4(out uint32 arg1, out string s);
- rpc str5(in uint64 seq_in,
- out uint64 seq_out,
- in uint32 arg1, in string s);
- rpc str6(in uint64 seq_in,
- out uint64 seq_out,
- out uint32 arg1, out string s);
-
- message arr0(uint32 arg1, char a[l]);
- message arr1(uint32 arg1, char a[l]);
- message arr2(uint32 arg1, char a[l]);
+ message stop();
+
+ rpc testrpc(in uint64 testin, out uint64 testout);
+ rpc testrpc2(in uint64 testin, out uint64 testout);
+
+ rpc outoforder(in uint64 seq_in,
+ out uint64 seq_out,
+ in uint64 testin,
+ out uint64 testout);
+
+ // The following messages are not used in practice, but
+ // exercise the THC Flounder back-end
+
+ message str0(uint32 arg1, String s[2048]);
+ message str1(uint32 arg1, String s[2048]);
+ message str2(uint32 arg1, String s[2048]);
+ rpc str3(in uint32 arg1, in String s[2048]);
+ rpc str4(out uint32 arg1, out String s[2048]);
+ rpc str5(in uint64 seq_in,
+ out uint64 seq_out,
+ in uint32 arg1, in String s[2048]);
+ rpc str6(in uint64 seq_in,
+ out uint64 seq_out,
+ out uint32 arg1, out String s[2048]);
+
+ message arr0(uint32 arg1, char a[l, 2048]);
+ message arr1(uint32 arg1, char a[l, 2048]);
+ message arr2(uint32 arg1, char a[l, 2048]);
};
message error_reply(errval err, uint64 state);
- message message_request(uint16 coreid, uint8 msg[size]);
+ message message_request(uint16 coreid, uint8 msg[size, 2048]);
message message_reply(uint16 coreid);
message bulk_message_request(uint16 coreid, uint64 id, uint64 size,
*/
interface serial "Serial characters" {
- message output(char data[len]);
- message input(char data[len]);
+ message output(char data[len, 128]);
+ message input(char data[len, 128]);
message associate_stdin();
};
*/
interface skb "SKB RPC Interface" {
- rpc run( in string input,
- out string output,
- out string str_error,
- out int int_error);
+ rpc run( in String input[2048],
+ out String output[4096],
+ out String str_error[512],
+ out int int_error);
-
/* Used by dist2 library (move in extra interface?) */
rpc get_identifier(out uint64 id);
rpc identify(in uint64 id);
- rpc get(in string query, out string output, out string error, out errval error_code);
- rpc set(in string input, out string error, out errval error_code);
- rpc del(in string query, out errval error_code);
-
- rpc subscribe(in string query, in uint64 id, out errval err);
+ rpc get(in String query[2048], out String output[2048], out String error[2048], out errval error_code);
+ rpc set(in String input[2048], out String error[2048], out errval error_code);
+ rpc del(in String query[2048], out errval error_code);
+
+ rpc subscribe(in String query[2048], in uint64 id, out errval err);
rpc unsubscribe(in uint64 id, out errval err);
- rpc publish(in string object, out errval err);
+ rpc publish(in String object[2048], out errval err);
- rpc lock(in string object, out errval err);
- rpc unlock(in string object, out errval err);
+ rpc lock(in String object[2048], out errval err);
+ rpc unlock(in String object[2048], out errval err);
};
uint8 status;
} ps_entry;
- rpc spawn_domain(in string path, in char argvbuf[argvbytes], in char envbuf[envbytes],
+ rpc spawn_domain(in String path[2048], in char argvbuf[argvbytes, 2048], in char envbuf[envbytes, 2048],
in uint8 flags, out errval err, out domainid domain_id);
- rpc spawn_domain_with_caps(in string path, in char argvbuf[argvbytes],
- in char envbuf[envbytes], in cap inheritcn_cap,
+ rpc spawn_domain_with_caps(in String path[2048], in char argvbuf[argvbytes, 2048],
+ in char envbuf[envbytes, 2048], in cap inheritcn_cap,
in cap argcn_cap, in uint8 flags, out errval err,
out domainid domain_id);
rpc wait(in domainid domain_id, in bool nohang, out uint8 exitcode, out errval err);
// XXX: Should be domainid instead of uint8, but it's not yet supported
- rpc get_domainlist(out uint8 domains[len]);
+ rpc get_domainlist(out uint8 domains[len, 2048]);
- rpc status(in domainid domain_id, out ps_entry ps_entry, out char argv[len],
+ rpc status(in domainid domain_id, out ps_entry ps_entry, out char argv[len, 2048],
out errval err);
// Capability debugging
* \param buffer Buffer holding characters.
* \param length Amount of characters in the buffer.
*/
- message characters(char buffer[length]);
+ message characters(char buffer[length, 2048]);
};
* \param opt Configuration option.
* \param argument Optional argument. Interpretation depends on opt.
*/
- message configuration(option opt, string argument);
+ message configuration(option opt, String argument[2048]);
/**
* \brief Signals that a client wants to teardown a connection.
interface test "Test interface" {
message basic(uint32 arg);
- message str(uint32 arg, string s);
+ message str(uint32 arg, String s[2048]);
message caps(uint32 arg, cap cap1, cap cap2);
- message buf(uint8 buf[buflen]);
+ message buf(uint8 buf[buflen, 2048]);
};
// read the name/type/size of the i'th entry in the given directory
// (yes, there's no protection against concurrent addition/deletion)
rpc readdir(in fh dir, in uint32 idx,
- out errval err, out string name, out bool isdir, out fsize size);
+ out errval err, out String name[2048], out bool isdir, out fsize size);
// look for a named entry in the given directory, return the fh if found
- rpc lookup(in fh dir, in string name,
+ rpc lookup(in fh dir, in String name[2048],
out errval err, out fh fh, out bool isdir);
// return the type/size of the given fh
// read/write: fairly straightforward
rpc read(in fh file, in offset offset, in fsize maxlen,
- out errval err, out uint8 data[retlen]);
- rpc write(in fh file, in offset offset, in uint8 data[len],
+ out errval err, out uint8 data[retlen, 2048]);
+ rpc write(in fh file, in offset offset, in uint8 data[len, 2048],
out errval err);
// read/write using bulk data
out errval err);
// create a new file in the given directory, fail if it already exists
- rpc create(in fh dir, in string name,
+ rpc create(in fh dir, in String name[2048],
out errval err, out fh fh);
// create a new subdirectory in the given directory
- rpc mkdir(in fh dir, in string name,
+ rpc mkdir(in fh dir, in String name[2048],
out errval err, out fh fh);
// delete a file or directory
*/
interface unixsock "UNIX socket" {
- message send(uint8 msg[size]);
+ message send(uint8 msg[size, 2048]);
};
interface usb_driver "USB Drive Interface" {
-
+
message device_detach_notify();
- message transfer_done_notify(uint32 tid, uint32 error, uint8 data[length]);
-};
\ No newline at end of file
+ message transfer_done_notify(uint32 tid, uint32 error, uint8 data[length, 2048]);
+};
interface usb_manager "USB Manager Interface" {
-
+
/* transfer setup parameters, keep in sync with struct usb_transfer_setup */
typedef struct {
uint32 max_bytes; ///< maximum bytes to to transfer
uint8 endpoint; ///< the associated endpoint of the transfer
uint8 iface; ///< the itnerface to use
} setup_param;
-
- /*
+
+ /*
* ----------------------------------------------------------------------
* connecting to the USB manager
- * ----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*/
-
- rpc connect(in iref driver_iref, in uint16 init_config, out uint32 ret_error, out uint8 ret_desc[length]);
+
+ rpc connect(in iref driver_iref, in uint16 init_config, out uint32 ret_error, out uint8 ret_desc[length, 2048]);
rpc device_disconnect_notify();
-
- /*
+
+ /*
* ----------------------------------------------------------------------
* Request handling
- * ----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*/
-
- rpc request_read(in uint8 request[req_length],
- out uint8 data[data_length],
+
+ rpc request_read(in uint8 request[req_length, 2048],
+ out uint8 data[data_length, 2048],
out uint32 ret_status);
-
- rpc request_write(in uint8 request[req_length],
- in uint8 data[data_length],
+
+ rpc request_write(in uint8 request[req_length, 2048],
+ in uint8 data[data_length, 2048],
out uint32 ret_status);
-
- rpc request(in uint8 request[req_length], out uint32 ret_status);
-
-
- /*
+
+ rpc request(in uint8 request[req_length, 2048], out uint32 ret_status);
+
+
+ /*
* ----------------------------------------------------------------------
* transfer management
- * ----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*/
-
- rpc transfer_setup(in uint8 type, in setup_param params,
- out uint32 ret_error, out uint32 ret_tid);
-
+
+ rpc transfer_setup(in uint8 type, in setup_param params,
+ out uint32 ret_error, out uint32 ret_tid);
+
rpc transfer_unsetup(in uint32 tid, out uint32 ret_error);
-
+
rpc transfer_start(in uint32 tid, out uint32 ret_error);
-
+
rpc transfer_stop(in uint32 tid, out uint32 ret_error);
-
- rpc transfer_status(in uint32 tid, out uint32 ret_error,
- out uint32 ret_actlen, out uint32 ret_length,
+
+ rpc transfer_status(in uint32 tid, out uint32 ret_error,
+ out uint32 ret_actlen, out uint32 ret_length,
out uint32 ret_actframes, out uint32 ret_numframes);
-
+
rpc transfer_state(in uint32 tid, out uint32 ret_error, out uint32 ret_state);
-
+
rpc transfer_clear_stall(in uint32 tid, out uint32 ret_error);
-
- rpc transfer_done_notify(out uint32 tid, out uint32 error, out uint8 data[length]);
-
- /*
+
+ rpc transfer_done_notify(out uint32 tid, out uint32 error, out uint8 data[length, 2048]);
+
+ /*
* ----------------------------------------------------------------------
* device management
- * ----------------------------------------------------------------------
+ * ----------------------------------------------------------------------
*/
-
+
rpc device_get_speed(out uint8 ret_speed);
-
+
rpc device_get_state(out uint8 ret_state);
-
+
rpc device_suspend(out uint32 ret_error);
-
+
rpc device_resume(out uint32 ret_error);
-
+
rpc device_powersave(in uint8 powerstate, out uint32 ret_error);
-
-
-};
\ No newline at end of file
+
+
+};
*/
interface xeon_phi "Xeon Phi Messaging Interface" {
-
- rpc domain_lookup(in char name[length],
+
+ rpc domain_lookup(in char name[length, 2048],
out uint64 domid,
out errval msgerr);
-
- rpc domain_wait(in char name[length],
+
+ rpc domain_wait(in char name[length, 2048],
out uint64 domid,
out errval msgerr);
-
- rpc domain_register(in char name[length],
+
+ rpc domain_register(in char name[length, 2048],
in uint64 domid,
out errval msgerr);
-
- rpc domain_init(in domainid domain,
+
+ rpc domain_init(in domainid domain,
in coreid core,
- in char name[length],
+ in char name[length, 2048],
out errval msgerr);
-
+
/*
* Spawning of Domains
- */
-
+ */
+
/**
* \
*/
- rpc spawn(in uint8 xid,
- in uint8 core,
- in char cmdline[length],
+ rpc spawn(in uint8 xid,
+ in uint8 core,
+ in char cmdline[length, 2048],
in uint8 flags,
out uint64 domainid,
out errval msgerr);
-
- rpc spawn_with_cap(in uint8 xid,
- in uint8 core,
- in char cmdline[length],
+
+ rpc spawn_with_cap(in uint8 xid,
+ in uint8 core,
+ in char cmdline[length, 2048],
in uint8 flags,
in cap capability,
out uint64 domainid,
out errval msgerr);
-
+
rpc kill(in uint8 xid,
- in uint64 domainid,
+ in uint64 domainid,
out errval msgerr);
-
-
- rpc chan_open_request(in uint8 xphi,
- in cap msgframe,
- in uint8 type,
+
+
+ rpc chan_open_request(in uint8 xphi,
+ in cap msgframe,
+ in uint8 type,
in uint64 domain,
in uint64 usrdata,
out errval msgerr);
-
-
+
+
rpc chan_open(in uint64 domain,
in uint64 usrdata,
- in cap msgframe,
+ in cap msgframe,
in uint8 type,
out errval msgerr);
-};
\ No newline at end of file
+};
interface xmplcr "Example call reply interface" {
message mycall(int i);
- message myresponse(string s);
-};
\ No newline at end of file
+ message myresponse(String s[2048]);
+};
interface xmplmsg "Example message interface" {
message msg_ints(int i, int j);
- message msg_string(string s);
-};
\ No newline at end of file
+ message msg_string(String s[2048]);
+};
*/
interface xmplrpc "Example rpc interface" {
- rpc myrpc(in int i, out string s);
-};
\ No newline at end of file
+ rpc myrpc(in int i, out String s[2048]);
+};
/** \file
- * \brief Example interface for use with thc
+ * \brief Example interface for use with thc
*/
/*
interface xmplthc "Example thc interface" {
message mymsg(int i);
message mycall(int i);
- message myresponse(string s);
- rpc myrpc(in int i, out string s);
+ message myresponse(String s[2048]);
+ rpc myrpc(in int i, out String s[2048]);
};
in uint8 direction,
in uint64 state,
out errval msg_err,
- out uint64 state);
+ out uint64 out_state);
/**
* \brief notifies the worker domain to obtain memory from the local
}
}
+/// Duplicate memory
+static inline void * memdup(const void *ptr, size_t size) {
+ void *res = malloc(size);
+ assert(res);
+ memcpy(res, ptr, size);
+ return res;
+}
+
/* XXX: glue junk for old IDC system, to be removed!! */
void messages_wait_and_handle_next(void);
/// size of the eh frame
size_t eh_frame_size;
- /// virtual address of the eh_frame
+ /// virtual address of the eh_frame
lvaddr_t eh_frame_hdr;
/// size of the eh frame
size_t eh_frame_hdr_size;
+
+ /// list of polled channels
+ struct waitset_chanstate *polled_channels;
};
#endif // BARRELFISH_DISPATCHER_H
}
/**
+ * \brief Check if a channel has data to receive
+ */
+
+static inline bool lmp_chan_can_recv(struct lmp_chan *lc)
+{
+ assert(lc);
+ assert(lc->endpoint);
+ return lmp_endpoint_can_recv(lc->endpoint);
+}
+
+/**
* \brief Set the receive capability slot for an LMP channel
*
* \param lc LMP channel
}
}
+/**
+ * \brief Get a receiving chanstate of LMP channel
+ */
+static inline struct waitset_chanstate * lmp_chan_get_receiving_channel(struct lmp_chan *chan)
+{
+ assert(chan->endpoint);
+ return &chan->endpoint->waitset_state;
+}
+
#include <barrelfish/lmp_chan_arch.h>
__END_DECLS
#include <barrelfish_kpi/registers_arch.h>
#include <barrelfish_kpi/dispatcher_handle.h>
#include <errors/errno.h>
+#include <barrelfish/waitset.h>
__BEGIN_DECLS
errval_t thread_detach(struct thread *thread);
void thread_pause(struct thread *thread);
-void thread_pause_and_capture_state(struct thread *thread,
+void thread_pause_and_capture_state(struct thread *thread,
arch_registers_state_t **ret_regs,
arch_registers_fpu_state_t **ret_fpuregs);
void thread_resume(struct thread *thread);
uintptr_t thread_get_id(struct thread *t);
void thread_set_id(uintptr_t id);
+uint32_t thread_set_token(struct waitset_chanstate *channel);
+void thread_clear_token(struct waitset_chanstate *channel);
+uint32_t thread_current_token(void);
+
+void thread_set_outgoing_token(uint32_t token);
+void thread_get_outgoing_token(uint32_t *token);
+
+struct flounder_rpc_context;
+
+void thread_set_rpc_in_progress(bool v);
+bool thread_get_rpc_in_progress(void);
+void thread_set_async_error(errval_t e);
+errval_t thread_get_async_error(void);
+
extern __thread thread_once_t thread_once_local_epoch;
extern void thread_once_internal(thread_once_t *control, void (*func)(void));
volatile struct ump_message **msg)
{
assert(msg != NULL);
+ assert(uc != NULL);
return ump_endpoint_recv(&uc->endpoint, msg);
}
+static inline errval_t ump_chan_can_recv(struct ump_chan *uc)
+{
+ assert(uc != NULL);
+ return ump_endpoint_can_recv(&uc->endpoint);
+}
+
static inline volatile struct ump_message *ump_chan_get_next(
struct ump_chan *uc, struct ump_control *ctrl)
{
ump_endpoint_migrate(&lc->endpoint, ws);
}
+static inline struct waitset_chanstate * ump_chan_get_receiving_channel(struct ump_chan *chan)
+{
+ return &chan->endpoint.waitset_state;
+}
+
+
__END_DECLS
#endif // BARRELFISH_UMP_CHAN_H
}
}
+static inline bool ump_endpoint_poll(struct waitset_chanstate *channel)
+{
+ struct ump_endpoint *ep = (struct ump_endpoint *)
+ ((char *)channel - offsetof(struct ump_endpoint, waitset_state));
+
+ if (ump_endpoint_can_recv(ep)) {
+ return true;
+ }
+ return false;
+}
+
+
__END_DECLS
#endif // LIBBARRELFISH_UMP_ENDPOINT_H
// This needs to be such that ump_payload defined in params in flounder/UMP.hs
// and the size of the UMP headers fits into it. It also needs to be a multiple
// of a cache-line.
-#define UMP_PAYLOAD_BYTES 64
-#define UMP_PAYLOAD_WORDS (UMP_PAYLOAD_BYTES / sizeof(uintptr_t) - 1)
-#define UMP_MSG_WORDS (UMP_PAYLOAD_WORDS + 1)
-#define UMP_MSG_BYTES (UMP_MSG_WORDS * sizeof(uintptr_t))
+#define UMP_MSG_BYTES 64
+#define UMP_MSG_WORDS (UMP_MSG_BYTES / sizeof(uintptr_t))
+#define UMP_PAYLOAD_BYTES (UMP_MSG_BYTES - sizeof(uint64_t))
+#define UMP_PAYLOAD_WORDS (UMP_PAYLOAD_BYTES / sizeof(uintptr_t))
/// Default size of a unidirectional UMP message buffer, in bytes
#define DEFAULT_UMP_BUFLEN (BASE_PAGE_SIZE / 2 / UMP_MSG_BYTES * UMP_MSG_BYTES)
struct ump_control {
ump_control_t epoch:UMP_EPOCH_BITS;
ump_control_t header:UMP_HEADER_BITS;
+ ump_control_t token:32;
};
struct ump_message {
uintptr_t data[UMP_PAYLOAD_WORDS] __attribute__((aligned (CACHELINE_BYTES)));
union {
struct ump_control control;
- uintptr_t raw;
+ uint64_t raw;
} header;
};
-STATIC_ASSERT((sizeof(struct ump_message)%CACHELINE_BYTES)==0,
+STATIC_ASSERT((sizeof(struct ump_message)%CACHELINE_BYTES)==0,
"Size of UMP message is not a multiple of cache-line size");
/// Type used for indices of UMP message slots
ump_control_t ctrl_epoch = c->buf[c->pos].header.control.epoch;
if (ctrl_epoch == c->epoch) {
return &c->buf[c->pos];
- } else {
- return NULL;
}
+ return NULL;
}
/**
{
volatile struct ump_message *msg = ump_impl_poll(c);
- if(msg != NULL) {
+ if (msg != NULL) {
if (++c->pos == c->bufmsgs) {
c->pos = 0;
c->epoch = !c->epoch;
}
return msg;
- } else {
- return NULL;
}
+ return NULL;
}
/**
// construct header
ctrl->epoch = c->epoch;
+ ctrl->token = 0;
#ifdef __x86_64__
if(debug_notify_syscall) {
#include <barrelfish/types.h>
#include <errors/errno.h>
#include <sys/cdefs.h>
+#include <barrelfish/dispatch.h>
__BEGIN_DECLS
CHAN_UNREGISTERED, ///< Initialised, but not yet registered on a waitset
CHAN_IDLE, ///< Has a registered event handler, but the event has not fired
CHAN_POLLED, ///< Idle and polled. Channel implementation must be called to check for pending events
- CHAN_PENDING ///< Has a pending event waiting to be delivered
+ CHAN_PENDING, ///< Has a pending event waiting to be delivered
+ CHAN_WAITING ///< There's no registered event handler (for now)
};
/**
struct event_closure closure; ///< Event closure to run when channel is ready
enum ws_chantype chantype; ///< Channel type
enum ws_chanstate state; ///< Channel event state
+
+ uint32_t token; ///< Token of an event
+ bool persistent; ///< Channel should be always registered
+ struct waitset_chanstate *polled_next, *polled_prev; ///< Dispatcher's polled queue
+ struct thread *wait_for; ///< Thread waiting for this event
};
/**
struct waitset {
struct waitset_chanstate *pending, ///< Channels with pending events
*polled, ///< Channels that need to be polled
- *idle; ///< All other channels on this waitset
+ *idle, ///< All other channels on this waitset
+ *waiting; ///< Channels waiting for an event handler registration
/// Queue of threads blocked on this waitset (when no events are pending)
struct thread *waiting_threads;
-
- /// Is a thread currently polling this waitset?
- volatile bool polling;
};
+void poll_channels_disabled(dispatcher_handle_t handle);
+
void waitset_init(struct waitset *ws);
errval_t waitset_destroy(struct waitset *ws);
errval_t get_next_event(struct waitset *ws, struct event_closure *retclosure);
-errval_t check_for_event(struct waitset *ws, struct event_closure *retclosure);
+errval_t get_next_event_disabled(struct waitset *ws, struct waitset_chanstate **retchan,
+ struct event_closure *retclosure, struct waitset_chanstate *waitfor, dispatcher_handle_t handle, bool debug);
+errval_t check_for_event(struct waitset *ws);
errval_t event_dispatch(struct waitset *ws);
+errval_t wait_for_channel(struct waitset *ws, struct waitset_chanstate *channel, errval_t *error_var);
+errval_t event_dispatch_disabled(struct waitset *ws, dispatcher_handle_t handle);
errval_t event_dispatch_debug(struct waitset *ws);
errval_t event_dispatch_non_block(struct waitset *ws);
///< Architecture generic kernel/user shared dispatcher struct
struct dispatcher_shared_generic {
- uint32_t disabled; ///< Disabled flag (Must be able to change atomically)
- uint32_t haswork; ///< Has work (ie. is runnable) (Must be able to change atomically)
+ uint32_t disabled; ///< Disabled flag (Must be able to change atomically)
+ uint32_t haswork; ///< Has work (ie. is runnable) (Must be able to change atomically)
- lvaddr_t udisp; ///< User-mode pointer to dispatcher
+ lvaddr_t udisp; ///< User-mode pointer to dispatcher
uint32_t lmp_delivered, lmp_seen; ///< # LMP words delivered and seen
lvaddr_t lmp_hint; ///< Hint for location of LMP
lvaddr_t dispatcher_run; ///< Run entry
lvaddr_t dispatcher_pagefault_disabled; ///< Disabled pagefault entry
lvaddr_t dispatcher_trap; ///< Trap entry
- systime_t systime; ///< System time when last dispatched/resumed (W/O to kernel)
- systime_t wakeup; ///< System time at which to wake dispatcher from sleep (R/O by kernel, on yield)
+ systime_t systime; ///< System time when last dispatched/resumed (W/O to kernel)
+ systime_t wakeup; ///< System time at which to wake dispatcher from sleep (R/O by kernel, on yield)
- char name[DISP_NAME_LEN];///< Name of domain, for debugging purposes
- uint32_t fpu_used; ///< Was FPU used while disabled?
- uint32_t fpu_trap; ///< State of FPU trap
-
- coreid_t curr_core_id; ///< Core id of current core, in this part so kernel can update
+ char name[DISP_NAME_LEN]; ///< Name of domain, for debugging purposes
+ uint32_t fpu_used; ///< Was FPU used while disabled?
+ uint32_t fpu_trap; ///< State of FPU trap
+
+ coreid_t curr_core_id; ///< Core id of current core, in this part so kernel can update
#ifdef __k1om__
uint8_t xeon_phi_id;
#endif
/// No-op continuation, to be passed to message send functions
#define NOP_CONT NOP_CLOSURE
+/// Blocking continuation, block until a sending completes
+void blocking_cont(void *v);
+#define BLOCKING_CONT MKCLOSURE(blocking_cont, NULL)
+
/// Utility macro to construct a continuation structure (handler & arg)
#define MKCONT(h,a) MKCLOSURE(h,a)
bool trigger_now);
void flounder_support_deregister_chan(struct waitset_chanstate *wc);
void flounder_support_waitset_chanstate_init(struct waitset_chanstate *wc);
+void flounder_support_waitset_chanstate_init_persistent(struct waitset_chanstate *wc);
void flounder_support_waitset_chanstate_destroy(struct waitset_chanstate *wc);
errval_t flounder_support_change_monitor_waitset(struct monitor_binding *mb,
struct waitset *ws);
lmp_send_flags_t flags,
const char *str,
size_t *pos, size_t *len);
-errval_t flounder_stub_lmp_recv_string(struct lmp_recv_msg *msg, char **str,
- size_t *pos, size_t *len);
+errval_t flounder_stub_lmp_recv_string(struct lmp_recv_msg *msg, char *str,
+ size_t *pos, size_t *len, size_t maxsize);
errval_t flounder_stub_lmp_send_buf(struct lmp_chan *chan,
lmp_send_flags_t flags, const void *buf,
size_t len, size_t *pos);
-errval_t flounder_stub_lmp_recv_buf(struct lmp_recv_msg *msg, void **buf,
- size_t *len, size_t *pos);
+errval_t flounder_stub_lmp_recv_buf(struct lmp_recv_msg *msg, void *buf,
+ size_t *len, size_t *pos, size_t maxsize);
__END_DECLS
ump_index_t last_ack; ///< Last acknowledgement we sent to remote
struct flounder_cap_state capst; ///< State for indirect cap tx/rx machinery
+ uint32_t token; ///< Outgoing message's token
};
void flounder_stub_ump_state_init(struct flounder_ump_state *s, void *binding);
size_t *pos, size_t *len);
errval_t flounder_stub_ump_recv_string(volatile struct ump_message *msg,
- char **str, size_t *pos, size_t *len);
+ char *str, size_t *pos, size_t *len,
+ size_t maxsize);
errval_t flounder_stub_ump_send_buf(struct flounder_ump_state *s,
int msgnum, const void *buf,
size_t len, size_t *pos);
errval_t flounder_stub_ump_recv_buf(volatile struct ump_message *msg,
- void **buf, size_t *len, size_t *pos);
+ void *buf, size_t *len, size_t *pos,
+ size_t maxsize);
+
/// Computes (from seq/ack numbers) whether we can currently send on the channel
static inline bool flounder_stub_ump_can_send(struct flounder_ump_state *s) {
- return (ump_index_t)(s->next_id - s->ack_id) <= s->chan.max_send_msgs;
+ bool r = (ump_index_t)(s->next_id - s->ack_id) <= s->chan.max_send_msgs;
+ return r;
}
#define ENABLE_MESSAGE_PASSING_TRACE 1
assert(s->chan.sendid != 0);
assert(msgtype < (1 << FL_UMP_MSGTYPE_BITS)); // check for overflow
ctrl->header = ((uintptr_t)msgtype << UMP_INDEX_BITS) | (uintptr_t)s->seq_id;
+ ctrl->token = s->token;
s->last_ack = s->seq_id;
s->next_id++;
}
union header { /* block header */
struct {
union header *ptr; /* next block if on free list */
+ unsigned magic; /* to mark malloced region */
unsigned size; /* size of this block */
} s;
Align x; /* force alignment of blocks */
errval_t skb_set_memory_affinity(void);
#define ELEMENT_NAME_BUF_SIZE 80
-#define SKB_REPLY_BUF_SIZE (128*1024)
struct list_parser_status {
char *s;
struct octopus_rpc_client *rpc_client = NULL;
char *attributes = NULL;
size_t attributes_len = 0;
- char *record = NULL;
octopus_trigger_id_t tid;
rpc_client = get_octopus_rpc_client();
/* Store record at octopus. */
err = rpc_client->vtbl.set_with_idcap(rpc_client, *session_id, attributes,
SET_DEFAULT, NOP_TRIGGER, false,
- &record, &tid, &error);
+ NULL, &tid, &error);
if (err_is_fail(err)) {
goto out;
}
void debug_printf(const char *fmt, ...)
{
+ struct thread *me = thread_self();
va_list argptr;
+ char id[32] = "-";
char str[256];
size_t len;
- len = snprintf(str, sizeof(str), "\033[34m%.*s.\033[31m%u.%"PRIuPTR"\033[0m: ",
- DISP_NAME_LEN, disp_name(), disp_get_core_id(), thread_id());
+ if (me)
+ snprintf(id, sizeof(id), "%"PRIuPTR, thread_get_id(me));
+ len = snprintf(str, sizeof(str), "\033[34m%.*s.\033[31m%u.%s\033[0m: ",
+ DISP_NAME_LEN, disp_name(), disp_get_core_id(), id);
if (len < sizeof(str)) {
va_start(argptr, fmt);
vsnprintf(str + len, sizeof(str) - len, fmt, argptr);
errval_t deferred_event_cancel(struct deferred_event *event)
{
enum ws_chanstate chanstate = event->waitset_state.state;
- dispatcher_handle_t dh = disp_disable();
- errval_t err = waitset_chan_deregister_disabled(&event->waitset_state);
+ dispatcher_handle_t handle = disp_disable();
+ errval_t err = waitset_chan_deregister_disabled(&event->waitset_state, handle);
if (err_is_ok(err) && chanstate != CHAN_PENDING) {
// remove from dispatcher queue
- struct dispatcher_generic *disp = get_dispatcher_generic(dh);
+ struct dispatcher_generic *disp = get_dispatcher_generic(handle);
if (event->prev == NULL) {
disp->deferred_events = event->next;
} else {
if (event->next != NULL) {
event->next->prev = event->prev;
}
- update_wakeup_disabled(dh);
+ update_wakeup_disabled(handle);
}
- disp_enable(dh);
+ disp_enable(handle);
return err;
}
// Trigger any send events for LMP channels
lmp_channels_retry_send_disabled(handle);
#endif // CONFIG_INTERCONNECT_DRIVER_LMP
+ // Check polled channels
+ poll_channels_disabled(handle);
// Run, saving state of previous thread if required
thread_run_disabled(handle);
///< Struct to maintain per dispatcher domain library state
struct domain_state {
iref_t iref; ///< Iref for the interdisp service
- struct interdisp_binding *b[MAX_CPUS];
+ struct interdisp_binding *binding[MAX_CPUS];
struct waitset interdisp_ws;
struct thread *default_waitset_handler;
struct thread *remote_wakeup_queue;
// XXX: Tell currently active interdisp-threads to handle default waitset
for(int i = 0; i < MAX_CPUS; i++) {
- struct interdisp_binding *b = domain_state->b[i];
+ struct interdisp_binding *b = domain_state->binding[i];
if(disp_get_core_id() != i &&
span_domain_state->core_id != i && b != NULL) {
struct domain_state *domain_state = get_domain_state();
/* Store the sending core's connection */
- domain_state->b[core_id] = b;
+ domain_state->binding[core_id] = b;
}
static struct interdisp_rx_vtbl interdisp_vtbl = {
/* Set it on the domain library state */
b->rx_vtbl = interdisp_vtbl;
- domain_state->b[state->cnt] = b;
+ domain_state->binding[state->cnt] = b;
// Send it our core id
err = b->tx_vtbl.span_eager_connect(b, NOP_CONT, disp_get_core_id());
USER_PANIC_ERR(err, "Binding to inter-dispatcher service");
}
} else {
- struct interdisp_binding *sb = domain_state->b[state->core_id];
+ struct interdisp_binding *sb = domain_state->binding[state->core_id];
/* Send initialized msg to the dispatcher that spanned us */
errval_t err2 = sb->tx_vtbl.
dispatcher_initialized(sb, NOP_CONT,
/* coreid_t core_id = disp_handle_get_core_id(thread->disp); */
coreid_t core_id = thread->coreid;
- assert(domain_state->b[core_id] != NULL);
+ assert(domain_state->binding[core_id] != NULL);
- struct interdisp_binding *b = domain_state->b[core_id];
+ struct interdisp_binding *b = domain_state->binding[core_id];
err = b->tx_vtbl.wakeup_thread(b, NOP_CONT, (genvaddr_t)(uintptr_t)thread);
if (err_is_fail(err)) {
USER_PANIC_ERR(err, "wakeup_thread");
waitset_chanstate_init(&domain_state->remote_wakeup_event,
CHANTYPE_EVENT_QUEUE);
for (int i = 0; i < MAX_CPUS; i++) {
- domain_state->b[i] = NULL;
+ domain_state->binding[i] = NULL;
}
waitset_init(&domain_state->interdisp_ws);
/* Wait to use the monitor binding */
struct monitor_binding *mcb = get_monitor_binding();
event_mutex_enqueue_lock(&mcb->mutex, &span_domain_state->event_qnode,
- (struct event_closure) {
- .handler = span_domain_request_sender_wrapper,
- .arg = span_domain_state });
+ (struct event_closure) {
+ .handler = span_domain_request_sender_wrapper,
+ .arg = span_domain_state });
-#if 1
while(!span_domain_state->initialized) {
event_dispatch(get_default_waitset());
}
/* Free state */
free(span_domain_state);
-#endif
return SYS_ERR_OK;
}
{
errval_t err;
struct domain_state *domain_state = get_domain_state();
- if (!domain_state->b[core_id]) {
+ if (!domain_state->binding[core_id]) {
return LIB_ERR_NO_SPANNED_DISP;
}
send_cap_err = SYS_ERR_OK;
cap_received = false;
- struct interdisp_binding *b = domain_state->b[core_id];
+ struct interdisp_binding *b = domain_state->binding[core_id];
err = b->tx_vtbl.send_cap_request(b, NOP_CONT, cap, (uintptr_t)&cap);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_SEND_CAP_REQUEST);
// Catch this early
assert_disabled(ds != NULL);
- if (ds->b[core_id] == NULL) {
+ if (ds->binding[core_id] == NULL) {
return LIB_ERR_NO_SPANNED_DISP;
}
struct domain_state *domain_state = get_domain_state();
errval_t err;
- if (domain_state->b[core_id] == NULL) {
+ if (domain_state->binding[core_id] == NULL) {
return LIB_ERR_NO_SPANNED_DISP;
}
- struct interdisp_binding *b = domain_state->b[core_id];
+ struct interdisp_binding *b = domain_state->binding[core_id];
struct create_thread_req *req = malloc(sizeof(*req));
req->reply_received = false;
// use special waitset to make sure loop exits properly.
struct domain_state *domain_state = get_domain_state();
errval_t err;
- if (domain_state->b[core_id] == NULL) {
+ if (domain_state->binding[core_id] == NULL) {
return LIB_ERR_NO_SPANNED_DISP;
}
- struct interdisp_binding *b = domain_state->b[core_id];
+ struct interdisp_binding *b = domain_state->binding[core_id];
struct join_thread_req *req = malloc(sizeof(*req));
req->reply_received = false;
// use special waitset to make sure loop exits properly.
thread_mutex_unlock(&em->tmutex);
} else {
// add ourselves to the thread queue and block
- // XXX: TODO: the mutex unlock and block on the queue must be atomic
- assert(!"this is broken without thread_block_and_release_mutex()");
- thread_mutex_unlock(&em->tmutex);
- void *wakeup_reason = thread_block(&em->tqueue);
+ dispatcher_handle_t handle = disp_disable();
+ thread_mutex_unlock_disabled(handle, &em->tmutex);
+ void *wakeup_reason = thread_block_and_release_spinlock_disabled(handle, &em->tqueue, NULL);
assert(wakeup_reason == em);
assert(em->locked);
#include <flounder/flounder_support_caps.h>
#include <if/monitor_defs.h>
+/// Special continuation for blocking
+void blocking_cont(void *v)
+{
+ debug_printf("%s: should never be called!\n", __func__);
+ assert(0);
+}
+
/*
* NB: many of these functions are trivial, but exist so that we don't need to
* expose private libbarrelfish headers or generated flounder headers to every
if (trigger_now) {
return waitset_chan_trigger_closure(ws, wc, ec);
} else {
+ if (ec.handler == blocking_cont) {
+ assert(!wc->wait_for); // this event should be received
+ wc->wait_for = thread_self(); // only by our thread
+ }
return waitset_chan_register(ws, wc, ec);
}
}
waitset_chanstate_init(wc, CHANTYPE_FLOUNDER);
}
+void flounder_support_waitset_chanstate_init_persistent(struct waitset_chanstate *wc)
+{
+ waitset_chanstate_init(wc, CHANTYPE_FLOUNDER);
+ wc->persistent = true;
+}
+
void flounder_support_waitset_chanstate_destroy(struct waitset_chanstate *wc)
{
waitset_chanstate_destroy(wc);
}
for (int i = 0; *pos < len && i < sizeof(uintptr_t); i++) {
- buf[(*pos)++] = (word & ((uintptr_t)0xff << shift_bits)) >> shift_bits;
+ buf[(*pos)++] = word >> shift_bits;
word <<= NBBY;
}
}
return err;
}
-errval_t flounder_stub_lmp_recv_buf(struct lmp_recv_msg *msg, void **bufp,
- size_t *len, size_t *pos)
+errval_t flounder_stub_lmp_recv_buf(struct lmp_recv_msg *msg, void *buf,
+ size_t *len, size_t *pos, size_t maxsize)
{
int msgpos;
+ assert(buf);
+
// is this the first fragment?
// if so, unmarshall the length and allocate a buffer
if (*pos == 0) {
}
*len = msg->words[0];
- if (*len == 0) {
- *bufp = NULL;
- } else {
- *bufp = malloc(*len);
- if (*bufp == NULL) {
- return LIB_ERR_MALLOC_FAIL;
- }
- }
+ assert(*len < maxsize);
msgpos = 1;
} else {
msgpos = 0;
}
- uint8_t *buf = *bufp;
-
// copy remainder of fragment to buffer
for (; msgpos < msg->buf.msglen && *pos < *len; msgpos++) {
putword(msg->words[msgpos], buf, pos, *len);
return flounder_stub_lmp_send_buf(chan, flags, str, *len, pos);
}
-errval_t flounder_stub_lmp_recv_string(struct lmp_recv_msg *msg, char **strp,
- size_t *pos, size_t *len)
+errval_t flounder_stub_lmp_recv_string(struct lmp_recv_msg *msg, char *str,
+ size_t *pos, size_t *len, size_t maxsize)
{
- return flounder_stub_lmp_recv_buf(msg, (void **)strp, len, pos);
+ errval_t err;
+
+ err = flounder_stub_lmp_recv_buf(msg, (void *)str, len, pos, maxsize);
+ if (*len == 0) {
+ str[0] = '\0';
+ }
+ return err;
}
#endif // CONFIG_INTERCONNECT_DRIVER_LMP
s->seq_id = 0;
s->ack_id = 0;
s->last_ack = 0;
+ s->token = 0;
flounder_stub_cap_state_init(&s->capst, binding);
}
}
errval_t flounder_stub_ump_recv_buf(volatile struct ump_message *msg,
- void **bufp, size_t *len, size_t *pos)
+ void *buf, size_t *len, size_t *pos,
+ size_t maxsize)
{
int msgpos;
+ assert(buf);
+
// is this the first fragment?
// if so, unmarshall the length and allocate a buffer
if (*pos == 0) {
*len = msg->data[0];
- if (*len == 0) {
- *bufp = NULL;
- } else {
- *bufp = malloc(*len);
- if (*bufp == NULL) {
- return LIB_ERR_MALLOC_FAIL;
- }
- }
-
+ assert(*len <= maxsize);
// XXX: skip as many words as the largest word size
msgpos = (sizeof(uint64_t) / sizeof(uintptr_t));
} else {
msgpos = 0;
}
- uint8_t *buf = *bufp;
-
// copy remainder of fragment to buffer
for (; msgpos < UMP_PAYLOAD_WORDS && *pos < *len; msgpos++) {
putword(msg->data[msgpos], buf, pos, *len);
}
errval_t flounder_stub_ump_recv_string(volatile struct ump_message *msg,
- char **strp, size_t *pos, size_t *len)
+ char *str, size_t *pos, size_t *len,
+ size_t maxsize)
{
- return flounder_stub_ump_recv_buf(msg, (void **)strp, len, pos);
+ errval_t err;
+
+ err = flounder_stub_ump_recv_buf(msg, (void *)str, len, pos, maxsize);
+ if (*len == 0) {
+ str[0] = '\0';
+ }
+ return err;
}
#endif // CONFIG_INTERCONNECT_DRIVER_UMP
bool paused; ///< Thread is paused (not runnable)
bool detached; ///< true if detached
bool joining; ///< true if someone is joining
- bool in_exception; ///< true iff running exception handler
+ bool in_exception; ///< true if running exception handler
bool used_fpu; ///< Ever used FPU?
#if defined(__x86_64__)
uint16_t thread_seg_selector; ///< Segment selector for TCB
arch_registers_fpu_state_t fpu_state; ///< FPU state
void *slab; ///< Base of slab block containing this TCB
uintptr_t id; ///< User-defined thread identifier
+
+ uint32_t token_number; ///< RPC next token
+ uint32_t token; ///< Token to be received
+ struct waitset_chanstate *channel; ///< on right channel
+
+ bool rpc_in_progress; ///< RPC in progress
+ errval_t async_error; ///< RPC async error
+ uint32_t outgoing_token; ///< Token of outgoing message
};
void thread_enqueue(struct thread *thread, struct thread **queue);
/* must only be called by dispatcher, while disabled */
void thread_init_disabled(dispatcher_handle_t handle, bool init_domain);
-/// Returns true iff there is non-threaded work to be done on this dispatcher
+/// Returns true if there is non-threaded work to be done on this dispatcher
/// (ie. if we still need to run)
static inline bool havework_disabled(dispatcher_handle_t handle)
{
#ifdef CONFIG_INTERCONNECT_DRIVER_LMP
|| disp->lmp_send_events_list != NULL
#endif
+ || disp->polled_channels != NULL
;
}
struct waitset_chanstate *chan,
struct event_closure closure,
dispatcher_handle_t handle);
-errval_t waitset_chan_deregister_disabled(struct waitset_chanstate *chan);
+errval_t waitset_chan_deregister_disabled(struct waitset_chanstate *chan,
+ dispatcher_handle_t handle);
errval_t waitset_chan_register_disabled(struct waitset *ws,
struct waitset_chanstate *chan,
struct event_closure closure);
struct waitset_chanstate *chan,
struct event_closure closure,
dispatcher_handle_t handle);
-errval_t waitset_chan_start_polling(struct waitset_chanstate *chan);
-errval_t waitset_chan_stop_polling(struct waitset_chanstate *chan);
#endif // BARRELFISH_WAITSET_CHAN_PRIV_H
struct bind_lmp_reply_state {
struct monitor_binding *b;
struct lmp_chan *lc;
- struct monitor_bind_lmp_reply_monitor__args args;
+ struct monitor_bind_lmp_reply_monitor__tx_args args;
struct event_queue_node qnode;
};
* \param dest Location of empty slot in which to create endpoint
* \param retep Double pointer to LMP endpoint, filled-in with allocated EP
*
- * This function mints into the given slot an endpoint capability to the
+ * This function mints into the given slot an endpoint capability to the
* current dispatcher.
*/
errval_t lmp_endpoint_create_in_slot(size_t buflen, struct capref dest,
dispatcher_handle_t handle = disp_disable();
struct dispatcher_generic *dp = get_dispatcher_generic(handle);
- errval_t err = waitset_chan_deregister_disabled(&ep->waitset_state);
+ errval_t err = waitset_chan_deregister_disabled(&ep->waitset_state, handle);
if (err_is_ok(err)) {
/* dequeue from poll list */
if (ep->next == ep) {
errval_t err;
struct morecore_state *state = get_morecore_state();
+ struct ram_alloc_state *ram_alloc_state = get_ram_alloc_state();
+ if(ram_alloc_state->ram_alloc_func != ram_alloc_fixed) {
+ if (bytes < LARGE_PAGE_SIZE) {
+ bytes = LARGE_PAGE_SIZE;
+ }
+
+ bytes = ROUND_UP(bytes, LARGE_PAGE_SIZE);
+ }
+
void *buf = NULL;
size_t mapped = 0;
size_t step = bytes;
struct bind_multihop_reply_state {
struct multihop_chan *mc;
struct monitor_binding *monitor_binding;
- struct monitor_multihop_bind_service_reply__args args;
+ struct monitor_multihop_bind_service_reply__tx_args args;
struct event_queue_node qnode;
};
return LIB_ERR_NAMESERVICE_NOT_BOUND;
}
- char* record = NULL;
- octopus_trigger_id_t tid;
- errval_t error_code;
- err = r->vtbl.get(r, iface, NOP_TRIGGER, &record, &tid, &error_code);
+
+ struct octopus_get_names_response__rx_args reply;
+ err = r->vtbl.get(r, iface, NOP_TRIGGER, reply.output, &reply.tid,
+ &reply.error_code);
if (err_is_fail(err)) {
goto out;
}
- err = error_code;
+ err = reply.error_code;
if (err_is_fail(err)) {
if (err_no(err) == OCT_ERR_NO_RECORD) {
err = err_push(err, LIB_ERR_NAMESERVICE_UNKNOWN_NAME);
}
uint64_t iref_number = 0;
- err = oct_read(record, "_ { iref: %d }", &iref_number);
+ err = oct_read(reply.output, "_ { iref: %d }", &iref_number);
if (err_is_fail(err) || iref_number == 0) {
err = err_push(err, LIB_ERR_NAMESERVICE_INVALID_NAME);
goto out;
}
out:
- free(record);
return err;
}
return LIB_ERR_NAMESERVICE_NOT_BOUND;
}
- char* record = NULL;
- errval_t error_code;
- err = r->vtbl.wait_for(r, iface, &record, &error_code);
+ struct octopus_wait_for_response__rx_args reply;
+ err = r->vtbl.wait_for(r, iface, reply.record, &reply.error_code);
if (err_is_fail(err)) {
goto out;
}
- err = error_code;
+ err = reply.error_code;
if (err_is_fail(err)) {
if (err_no(err) == OCT_ERR_NO_RECORD) {
err = err_push(err, LIB_ERR_NAMESERVICE_UNKNOWN_NAME);
}
uint64_t iref_number = 0;
- err = oct_read(record, "_ { iref: %d }", &iref_number);
+ err = oct_read(reply.record, "_ { iref: %d }", &iref_number);
if (err_is_fail(err)) {
err = err_push(err, LIB_ERR_NAMESERVICE_INVALID_NAME);
goto out;
}
out:
- free(record);
return err;
}
}
snprintf(record, len+1, format, iface, iref);
- char* ret = NULL;
octopus_trigger_id_t tid;
errval_t error_code;
- err = r->vtbl.set(r, record, 0, NOP_TRIGGER, 0, &ret, &tid, &error_code);
+ err = r->vtbl.set(r, record, 0, NOP_TRIGGER, 0, NULL, &tid, &error_code);
if (err_is_fail(err)) {
goto out;
}
}
// FIXME: world's most (kinda less now) broken implementation...
-
- char* buffer = NULL;
- errval_t error_code;
- octopus_trigger_id_t tid;
-
char** names = NULL;
size_t count = 0;
-
+
static char* spawnds = "r'spawn.[0-9]+' { iref: _ }";
- err = r->vtbl.get_names(r, spawnds, NOP_TRIGGER, &buffer, &tid, &error_code);
- if (err_is_fail(err) || err_is_fail(error_code)) {
+ struct octopus_get_names_response__rx_args reply;
+ err = r->vtbl.get_names(r, spawnds, NOP_TRIGGER, reply.output, &reply.tid,
+ &reply.error_code);
+ if (err_is_fail(err) || err_is_fail(reply.error_code)) {
err = err_push(err, SPAWN_ERR_FIND_SPAWNDS);
goto out;
}
- err = oct_parse_names(buffer, &names, &count);
+ err = oct_parse_names(reply.output, &names, &count);
if (err_is_fail(err)) {
goto out;
}
}
out:
- free(buffer);
oct_free_names(names, count);
return err;
}
}
assert(cl != NULL);
- err = cl->vtbl.get_domainlist(cl, domains, len);
+ struct spawn_get_domainlist_response__rx_args reply;
+ err = cl->vtbl.get_domainlist(cl, reply.domains, len);
if (err_is_fail(err)) {
USER_PANIC_ERR(err, "get_domainlist");
}
+ *domains = memdup(reply.domains, *len);
return SYS_ERR_OK;
}
}
assert(cl != NULL);
- err = cl->vtbl.status(cl, domain, (spawn_ps_entry_t *)pse, argbuf, arglen,
- reterr);
+ struct spawn_status_response__rx_args reply;
+ err = cl->vtbl.status(cl, domain, (spawn_ps_entry_t *)pse, reply.argv,
+ arglen, reterr);
if (err_is_fail(err)) {
USER_PANIC_ERR(err, "status");
}
+ *argbuf = memdup(reply.argv, *arglen);
return SYS_ERR_OK;
}
newthread->used_fpu = false;
newthread->paused = false;
newthread->slab = NULL;
+ newthread->token = 0;
+ newthread->token_number = 1;
+
+ newthread->rpc_in_progress = false;
+ newthread->async_error = SYS_ERR_OK;
}
/**
me->id = id;
}
+uint32_t thread_set_token(struct waitset_chanstate *channel)
+{
+ struct thread *me = thread_self();
+ // generate new token
+ uint32_t outgoing_token = (uint32_t)((me->id << 16) |
+ (me->coreid << 24) | ((me->token_number & 255) << 8)) | 1;
+ assert(me->token == 0);
+ me->token_number++;
+ me->token = outgoing_token & ~1; // wait for this token
+ me->channel = channel; // on that channel
+ return outgoing_token;
+}
+
+void thread_clear_token(struct waitset_chanstate *channel)
+{
+ struct thread *me = thread_self();
+
+ me->token = 0; // don't wait anymore
+ me->channel = NULL;
+}
+
+uint32_t thread_current_token(void)
+{
+ return thread_self()->token;
+}
+
+void thread_set_outgoing_token(uint32_t token)
+{
+ struct thread *me = thread_self();
+
+ assert(!me->outgoing_token);
+ me->outgoing_token = token;
+}
+
+void thread_get_outgoing_token(uint32_t *token)
+{
+ struct thread *me = thread_self();
+ // if thread's outgoing token is set, get it
+ if (me->outgoing_token) {
+ *token = me->outgoing_token;
+ me->outgoing_token = 0;
+ }
+}
+
+void thread_set_rpc_in_progress(bool v)
+{
+ thread_self()->rpc_in_progress = v;
+}
+
+bool thread_get_rpc_in_progress(void)
+{
+ return thread_self()->rpc_in_progress;
+}
+
+void thread_set_async_error(errval_t e)
+{
+ thread_self()->async_error = e;
+}
+
+errval_t thread_get_async_error(void)
+{
+ return thread_self()->async_error;
+}
+
/**
* \brief Yield the calling thread
*
}
} while(next->yield_epoch == disp_gen->timeslice);
+ poll_channels_disabled(handle);
+
if (next != me) {
fpu_context_switch(disp_gen, next);
disp_gen->current = next;
*/
struct thread *thread_unblock_one(struct thread **queue, void *reason)
{
- return thread_unblock_one_disabled(disp_disable(), queue, reason);
+ struct thread *thread;
+
+ dispatcher_handle_t handle = disp_disable();
+ thread = thread_unblock_one_disabled(handle, queue, reason);
+ disp_enable(handle);
+ return thread;
}
/**
struct bind_ump_reply_state {
struct monitor_binding *b;
struct ump_chan *uc;
- struct monitor_bind_ump_reply_monitor__args args;
+ struct monitor_bind_ump_reply_monitor__tx_args args;
struct event_queue_node qnode;
};
// send back a bind success/failure message to the monitor
err =
- st->b->tx_vtbl.bind_ump_reply_monitor(st->b, NOP_CONT, st->args.mon_id,
+ st->b->tx_vtbl.bind_ump_reply_monitor(b, NOP_CONT, st->args.mon_id,
st->args.conn_id, st->args.err,
st->args.notify);
if (err_is_ok(err)) {
void *buf;
err = vspace_map_one_frame_attr(&buf, framesize, uc->frame, UMP_MAP_ATTR,
NULL, &uc->vregion);
- if (err_is_fail(err)) {
+ if (err_is_fail(err)) {
cap_destroy(uc->frame);
return err_push(err, LIB_ERR_VSPACE_MAP);
}
assert(ep != NULL);
assert(ws != NULL);
- if (ump_endpoint_can_recv(ep)) { // trigger event immediately
+ if (ump_endpoint_poll(&ep->waitset_state)) { // trigger event immediately
return waitset_chan_trigger_closure(ws, &ep->waitset_state, closure);
} else {
return waitset_chan_register_polled(ws, &ep->waitset_state, closure);
#include <stdio.h>
#include <string.h>
+#include <flounder/flounder.h>
+
#ifdef CONFIG_INTERCONNECT_DRIVER_UMP
# include <barrelfish/ump_endpoint.h>
#endif
-#if defined(__k1om__) || defined(__aarch64__)
-#include <barrelfish_kpi/asm_inlines_arch.h>
-static inline cycles_t cyclecount(void)
+/// Dequeue a chanstate from a queue
+static void dequeue(struct waitset_chanstate **queue, struct waitset_chanstate *chan)
{
- return rdtsc();
+ if (chan->next == chan) {
+ assert(chan->prev == chan);
+ assert(*queue == chan);
+ *queue = NULL;
+ } else {
+ chan->prev->next = chan->next;
+ chan->next->prev = chan->prev;
+ if (*queue == chan) {
+ *queue = chan->next;
+ }
+ }
+ chan->prev = chan->next = NULL;
}
-#elif defined(__x86_64__) || defined(__i386__)
-#include <arch/x86/barrelfish_kpi/asm_inlines_arch.h>
-static inline cycles_t cyclecount(void)
+
+/// Enqueue a chanstate on a queue
+static void enqueue(struct waitset_chanstate **queue, struct waitset_chanstate *chan)
{
- return rdtsc();
+ if (*queue == NULL) {
+ *queue = chan;
+ chan->next = chan->prev = chan;
+ } else {
+ chan->next = *queue;
+ chan->prev = (*queue)->prev;
+ chan->next->prev = chan;
+ chan->prev->next = chan;
+ }
}
-#elif defined(__arm__) && defined(__gem5__)
-/**
- * XXX: Gem5 doesn't support the ARM performance monitor extension
- * therefore we just poll a fixed number of times instead of using
- * cycle counts. POLL_COUNT is deliberately set to 42, guess why! ;)
- */
-#define POLL_COUNT 42
-#elif defined(__aarch64__) && defined(__gem5__)
-#define POLL_COUNT 42
-#elif defined(__arm__)
-#include <arch/arm/barrelfish_kpi/asm_inlines_arch.h>
-static inline cycles_t cyclecount(void)
+
+/// Dequeue a chanstate from polled queue
+static void dequeue_polled(struct waitset_chanstate **queue,
+ struct waitset_chanstate *chan)
{
- return get_cycle_count();
+ if (chan->polled_next == chan) {
+ assert(chan->polled_prev == chan);
+ assert(*queue == chan);
+ *queue = NULL;
+ } else {
+ chan->polled_prev->polled_next = chan->polled_next;
+ chan->polled_next->polled_prev = chan->polled_prev;
+ if (*queue == chan) {
+ *queue = chan->polled_next;
+ }
+ }
+ chan->polled_prev = chan->polled_next = NULL;
}
-#else
-static inline cycles_t cyclecount(void)
+
+/// Enqueue a chanstate on polled queue
+static void enqueue_polled(struct waitset_chanstate **queue,
+ struct waitset_chanstate *chan)
{
- USER_PANIC("called on non-x86 architecture. why are we polling?");
- return 0;
+ if (*queue == NULL) {
+ *queue = chan;
+ chan->polled_next = chan->polled_prev = chan;
+ } else {
+ chan->polled_next = *queue;
+ chan->polled_prev = (*queue)->polled_prev;
+ chan->polled_next->polled_prev = chan;
+ chan->polled_prev->polled_next = chan;
+ }
}
-#endif
-
-// FIXME: bogus default value. need to measure this at boot time
-#define WAITSET_POLL_CYCLES_DEFAULT 2000
-
-/// Maximum number of cycles to spend polling channels before yielding CPU
-cycles_t waitset_poll_cycles = WAITSET_POLL_CYCLES_DEFAULT;
/**
* \brief Initialise a new waitset
void waitset_init(struct waitset *ws)
{
assert(ws != NULL);
- ws->pending = ws->polled = ws->idle = NULL;
+ ws->pending = ws->polled = ws->idle = ws->waiting = NULL;
ws->waiting_threads = NULL;
- ws->polling = false;
}
/**
return SYS_ERR_OK;
}
-/// Returns a channel with a pending event on the given waitset, or NULL
-static struct waitset_chanstate *get_pending_event_disabled(struct waitset *ws)
+/// Check if a thread can receive an event
+static bool waitset_check_token(struct waitset_chanstate *chan,
+ struct thread *thread)
{
- // are there any pending events on the waitset?
- if (ws->pending == NULL) {
- return NULL;
- }
-
- // dequeue next pending event
- struct waitset_chanstate *chan = ws->pending;
- if (chan->next == chan) {
- assert_disabled(chan->prev == chan);
- ws->pending = NULL;
- } else {
- ws->pending = chan->next;
- chan->prev->next = chan->next;
- chan->next->prev = chan->prev;
- }
-#ifndef NDEBUG
- chan->prev = chan->next = NULL;
-#endif
-
- // mark not pending
- assert_disabled(chan->state == CHAN_PENDING);
- chan->state = CHAN_UNREGISTERED;
- chan->waitset = NULL;
+ bool res = false;
- return chan;
+ if (chan->wait_for) // if a thread is waiting for this specific event
+ res = chan->wait_for == thread;
+ else
+ res = (chan->token & 1 && !thread->token) // incoming token is a request
+ // and a thread is not waiting for a token
+ || (!chan->token && chan != thread->channel) // there's no token
+ // and a thread is not waiting specifically for that event
+ || (chan->token == thread->token && chan == thread->channel);
+ // there is a token and it matches thread's token and event
+ return res;
}
-#ifdef CONFIG_INTERCONNECT_DRIVER_UMP
-/**
- * \brief Poll an incoming UMP endpoint.
- * This is logically part of the UMP endpoint implementation, but placed here
- * for easier inlining.
- */
-static inline void ump_endpoint_poll(struct waitset_chanstate *chan)
+/// Returns a channel with a pending event on the given waitset matching
+/// our thread
+static struct waitset_chanstate *get_pending_event_disabled(struct waitset *ws,
+ struct waitset_chanstate *chan)
{
- /* XXX: calculate location of endpoint from waitset channel state */
- struct ump_endpoint *ep = (struct ump_endpoint *)
- ((char *)chan - offsetof(struct ump_endpoint, waitset_state));
+ struct thread *me = thread_self();
- if (ump_endpoint_can_recv(ep)) {
- errval_t err = waitset_chan_trigger(chan);
- assert(err_is_ok(err)); // should not be able to fail
+ if (chan) { // channel that we wait for
+ if (chan->state == CHAN_PENDING && waitset_check_token(chan, me)) {
+ return chan;
+ }
+ if (chan->state == CHAN_WAITING && waitset_check_token(chan, me)) {
+ return chan;
+ }
+ }
+ // check a waiting queue for matching event
+ for (chan = ws->waiting; chan; ) {
+ if (waitset_check_token(chan, me)) {
+ assert_disabled(chan->state == CHAN_WAITING);
+ return chan;
+ }
+ chan = chan->next;
+ if (chan == ws->waiting)
+ break;
+ }
+ // check a pending queue for matching event
+ for (chan = ws->pending; chan;) {
+ if (waitset_check_token(chan, me)) {
+ assert_disabled(chan->state == CHAN_PENDING);
+ return chan;
+ }
+ chan = chan->next;
+ if (chan == ws->pending)
+ break;
}
+ return NULL;
}
-#endif // CONFIG_INTERCONNECT_DRIVER_UMP
-
void arranet_polling_loop_proxy(void) __attribute__((weak));
void arranet_polling_loop_proxy(void)
assert(err_is_ok(err)); // should not be able to fail
}
-/// Helper function that knows how to poll the given channel, based on its type
-static void poll_channel(struct waitset_chanstate *chan)
-{
- switch (chan->chantype) {
+/// Check polled channels
+void poll_channels_disabled(dispatcher_handle_t handle) {
+ struct dispatcher_generic *dp = get_dispatcher_generic(handle);
+ struct waitset_chanstate *chan;
+
+ if (!dp->polled_channels)
+ return;
+ chan = dp->polled_channels;
+ do {
+ switch (chan->chantype) {
#ifdef CONFIG_INTERCONNECT_DRIVER_UMP
- case CHANTYPE_UMP_IN:
- ump_endpoint_poll(chan);
- break;
+ case CHANTYPE_UMP_IN: {
+ if (ump_endpoint_poll(chan)) {
+ errval_t err = waitset_chan_trigger_disabled(chan, handle);
+ assert(err_is_ok(err)); // should not fail
+ if (!dp->polled_channels) // restart scan
+ return;
+ chan = dp->polled_channels;
+ continue;
+ } else
+ chan = chan->polled_next;
+ } break;
#endif // CONFIG_INTERCONNECT_DRIVER_UMP
-
- case CHANTYPE_LWIP_SOCKET:
- arranet_polling_loop_proxy();
- break;
-
- case CHANTYPE_AHCI:
- poll_ahci(chan);
- break;
-
- default:
- assert(!"invalid channel type to poll!");
- }
+ case CHANTYPE_LWIP_SOCKET:
+ arranet_polling_loop_proxy();
+ break;
+ case CHANTYPE_AHCI:
+ poll_ahci(chan);
+ break;
+ default:
+ assert(!"invalid channel type to poll!");
+ }
+ } while (chan != dp->polled_channels);
}
-// pollcycles_*: arch-specific implementation for polling.
-// Used by get_next_event().
-//
-// pollcycles_reset() -- return the number of pollcycles we want to poll for
-// pollcycles_update() -- update the pollcycles variable. This is needed for
-// implementations where we don't have a cycle counter
-// and we just count the number of polling operations
-// performed
-// pollcycles_expired() -- check if pollcycles have expired
-//
-// We might want to move them to architecture-specific files, and/or create a
-// cleaner interface. For now, I just wanted to keep them out of
-// get_next_event()
-
-#if defined(__ARM_ARCH_7A__) && defined(__GNUC__) \
- && __GNUC__ == 4 && __GNUC_MINOR__ <= 6 && __GNUC_PATCHLEVEL__ <= 3
-static __attribute__((noinline, unused))
-#else
-static inline
-#endif
-cycles_t pollcycles_reset(void)
+/// Re-register a channel (if persistent)
+static void reregister_channel(struct waitset *ws, struct waitset_chanstate *chan,
+ dispatcher_handle_t handle)
{
- cycles_t pollcycles;
-#if defined(__arm__) && !defined(__gem5__)
- reset_cycle_counter();
- pollcycles = waitset_poll_cycles;
-#elif defined(__arm__) && defined(__gem5__)
- pollcycles = 0;
-#elif defined(__aarch64__) && defined(__gem5__)
- pollcycles = 0;
-#else
- pollcycles = cyclecount() + waitset_poll_cycles;
-#endif
- return pollcycles;
-}
+ assert(chan->waitset == ws);
+ if (chan->state == CHAN_PENDING) {
+ dequeue(&ws->pending, chan);
+ } else {
+ assert(chan->state == CHAN_WAITING);
+ dequeue(&ws->waiting, chan);
+ }
-#if defined(__ARM_ARCH_7A__) && defined(__GNUC__) \
- && __GNUC__ == 4 && __GNUC_MINOR__ <= 6 && __GNUC_PATCHLEVEL__ <= 3
-static __attribute__((noinline, unused))
-#else
-static inline
-#endif
-cycles_t pollcycles_update(cycles_t pollcycles)
-{
- cycles_t ret = pollcycles;
- #if defined(__arm__) && defined(__gem5__)
- ret++;
- #elif defined(__aarch64__) && defined(__gem5__)
- ret++;
- #endif
- return ret;
+ chan->token = 0;
+ if (chan->chantype == CHANTYPE_UMP_IN
+ || chan->chantype == CHANTYPE_LWIP_SOCKET
+ || chan->chantype == CHANTYPE_AHCI) {
+ enqueue(&ws->polled, chan);
+ enqueue_polled(&get_dispatcher_generic(handle)->polled_channels, chan);
+ chan->state = CHAN_POLLED;
+ } else {
+ enqueue(&ws->idle, chan);
+ chan->state = CHAN_IDLE;
+ }
}
-#if defined(__ARM_ARCH_7A__) && defined(__GNUC__) \
- && __GNUC__ == 4 && __GNUC_MINOR__ <= 6 && __GNUC_PATCHLEVEL__ <= 3
-static __attribute__((noinline, unused))
-#else
-static inline
-#endif
-bool pollcycles_expired(cycles_t pollcycles)
+/// Find a thread that is able to receive an event
+static struct thread * find_recipient(struct waitset *ws,
+ struct waitset_chanstate *channel, struct thread *me)
{
- bool ret;
- #if defined(__arm__) && !defined(__gem5__)
- ret = (cyclecount() > pollcycles || is_cycle_counter_overflow());
- #elif defined(__arm__) && defined(__gem5__)
- ret = pollcycles >= POLL_COUNT;
- #elif defined(__aarch64__) && defined(__gem5__)
- ret = pollcycles >= POLL_COUNT;
- #else
- ret = cyclecount() > pollcycles;
- #endif
- return ret;
+ struct thread *t = ws->waiting_threads;
+
+ if (!t)
+ return NULL;
+ do {
+ if (waitset_check_token(channel, t))
+ return t;
+ t = t->next;
+ } while (t != ws->waiting_threads);
+ return ws->waiting_threads;
}
-static errval_t get_next_event_debug(struct waitset *ws,
- struct event_closure *retclosure, bool debug)
+/// Wake up other thread if there's more pending events
+static void wake_up_other_thread(dispatcher_handle_t handle, struct waitset *ws)
{
- struct waitset_chanstate *chan;
- bool was_polling = false;
- cycles_t pollcycles;
-
- assert(ws != NULL);
- assert(retclosure != NULL);
-
- // unconditionally disable ourselves and check for events
- // if we decide we have to start polling, we'll jump back up here
- goto check_for_events;
-
- /* ------------ POLLING LOOP; RUNS WHILE ENABLED ------------ */
-polling_loop:
- was_polling = true;
- assert(ws->polling); // this thread is polling
- // get the amount of cycles we want to poll for
- pollcycles = pollcycles_reset();
-
- // while there are no pending events, poll channels
- while (ws->polled != NULL && ws->pending == NULL) {
- struct waitset_chanstate *nextchan = NULL;
- // NB: Polling policy is to return as soon as a pending event
- // appears, not bother looking at the rest of the polling queue
- for (chan = ws->polled;
- chan != NULL && chan->waitset == ws && chan->state == CHAN_POLLED
- && ws->pending == NULL;
- chan = nextchan) {
-
- nextchan = chan->next;
- poll_channel(chan);
- // update pollcycles
- pollcycles = pollcycles_update(pollcycles);
- // yield the thread if we exceed the cycle count limit
- if (ws->pending == NULL && pollcycles_expired(pollcycles)) {
- if (debug) {
- if (strcmp(disp_name(), "netd") != 0) {
- // Print the callback trace so that we know which call is leading
- // the schedule removal and
- printf("%s: callstack: %p %p %p %p\n", disp_name(),
- __builtin_return_address(0),
- __builtin_return_address(1),
- __builtin_return_address(2),
- __builtin_return_address(3));
- }
-
- }
- thread_yield();
- pollcycles = pollcycles_reset();
- }
- }
+ if (ws->pending && ws->waiting_threads) {
+ struct thread *t;
- // ensure that we restart polling from the place we left off here,
- // if the next channel is a valid one
- if (nextchan != NULL && nextchan->waitset == ws
- && nextchan->state == CHAN_POLLED) {
- ws->polled = nextchan;
- }
+ t = thread_unblock_one_disabled(handle, &ws->waiting_threads, NULL);
+ assert_disabled(t == NULL); // shouldn't see a remote thread
}
+}
- /* ------------ STATE MACHINERY; RUNS WHILE DISABLED ------------ */
-check_for_events: ;
- dispatcher_handle_t handle = disp_disable();
+/**
+ * \brief Get next pending event
+ *
+ * Check if there is a pending event that matches current thread and return it.
+ * Pending events are in a pending queue and in a waiting queue.
+ * A pending event then will be removed from a pending/waiting queue and become
+ * unregistered or, if it's persistent, will be re-registered to an idle queue
+ * or a polled queue (UMP channels) of a waitset.
+ * If there's no pending event, block this thread.
+ * If there's a pending event but it doesn't match our thread, don't remove it
+ * from a pending queue and wake up a matching thread.
+ * If there's no matching thread, add it to a waiting queue.
+ *
+ * \param ws Waitset with sources of events
+ * \param retchannel Holder of returned event
+ * \param retclosure Holder of returned closure
+ * \param waitfor Specific event that we're waiting for (can be NULL)
+ * \param handle Dispatcher's handle
+ * \param debug Debug mode (not used)
+ */
- // are there any pending events on the waitset?
- chan = get_pending_event_disabled(ws);
- if (chan != NULL) {
- // if we need to poll, and we have a blocked thread, wake it up to do so
- if (was_polling && ws->polled != NULL && ws->waiting_threads != NULL) {
- // start a blocked thread polling
- struct thread *t;
- t = thread_unblock_one_disabled(handle, &ws->waiting_threads, NULL);
- assert_disabled(t == NULL); // shouldn't see a remote thread
- } else if (was_polling) {
- // I'm stopping polling, and there is nobody else
- assert_disabled(ws->polling);
- ws->polling = false;
+errval_t get_next_event_disabled(struct waitset *ws,
+ struct waitset_chanstate **retchannel, struct event_closure *retclosure,
+ struct waitset_chanstate *waitfor, dispatcher_handle_t handle, bool debug)
+{
+ struct waitset_chanstate * chan;
+
+ for (;;) {
+ chan = get_pending_event_disabled(ws, waitfor); // get our event
+ if (chan) {
+ *retchannel = chan;
+ *retclosure = chan->closure;
+ chan->wait_for = NULL;
+ chan->token = 0;
+ if (chan->persistent)
+ reregister_channel(ws, chan, handle);
+ else
+ waitset_chan_deregister_disabled(chan, handle);
+ wake_up_other_thread(handle, ws);
+ return SYS_ERR_OK;
}
- disp_enable(handle);
-
- *retclosure = chan->closure;
- return SYS_ERR_OK;
- }
-
- // If we got here and there are channels to poll but no-one is polling,
- // then either we never polled, or we lost a race on the channel we picked.
- // Either way, we'd better start polling again.
- if (ws->polled != NULL && (was_polling || !ws->polling)) {
- if (!was_polling) {
- ws->polling = true;
+ chan = ws->pending; // check a pending queue
+ if (!chan) { // if nothing then wait
+ thread_block_disabled(handle, &ws->waiting_threads);
+ disp_disable();
+ } else { // something but it's not our event
+ if (!ws->waiting_threads) { // no other thread interested in
+ dequeue(&ws->pending, chan);
+ enqueue(&ws->waiting, chan);
+ chan->state = CHAN_WAITING;
+ chan->waitset = ws;
+ } else {
+ // find a matching thread
+ struct thread *t;
+ for (t = ws->waiting_threads; t; ) {
+ if (waitset_check_token(chan, t)) { // match found, wake it
+ ws->waiting_threads = t;
+ t = thread_unblock_one_disabled(handle,
+ &ws->waiting_threads, chan);
+ assert_disabled(t == NULL); // shouldn't see a remote thread
+ break;
+ }
+ t = t->next;
+ if (t == ws->waiting_threads) { // no recipient found
+ dequeue(&ws->pending, chan);
+ enqueue(&ws->waiting, chan);
+ chan->state = CHAN_WAITING;
+ chan->waitset = ws;
+ break;
+ }
+ }
+ }
}
- disp_enable(handle);
- goto polling_loop;
- }
-
- // otherwise block awaiting an event
- chan = thread_block_disabled(handle, &ws->waiting_threads);
-
- if (chan == NULL) {
- // not a real event, just a wakeup to get us to start polling!
- assert(ws->polling);
- goto polling_loop;
- } else {
- *retclosure = chan->closure;
- return SYS_ERR_OK;
}
}
*/
errval_t get_next_event(struct waitset *ws, struct event_closure *retclosure)
{
- return get_next_event_debug(ws, retclosure, false);
+ dispatcher_handle_t handle = disp_disable();
+ struct waitset_chanstate *channel;
+ errval_t err = get_next_event_disabled(ws, &channel, retclosure, NULL,
+ handle, false);
+ disp_enable(handle);
+ return err;
}
/**
- * \brief Return next event on given waitset, if one is already pending
+ * \brief Check if there is an event pending on given waitset
*
* This is essentially a non-blocking variant of get_next_event(). It should be
* used with great care, to avoid the creation of busy-waiting loops.
*
* \param ws Waitset
- * \param retclosure Pointer to storage space for returned event closure
*
* \returns LIB_ERR_NO_EVENT if nothing is pending
*/
-errval_t check_for_event(struct waitset *ws, struct event_closure *retclosure)
+static errval_t check_for_event_disabled(struct waitset *ws, dispatcher_handle_t handle)
{
struct waitset_chanstate *chan;
- int pollcount = 0;
-
- assert(ws != NULL);
- assert(retclosure != NULL);
- recheck: ;
- // are there any pending events on the waitset?
- dispatcher_handle_t handle = disp_disable();
- chan = get_pending_event_disabled(ws);
- disp_enable(handle);
+ poll_channels_disabled(handle);
+ chan = get_pending_event_disabled(ws, NULL);
if (chan != NULL) {
- *retclosure = chan->closure;
return SYS_ERR_OK;
}
+ return LIB_ERR_NO_EVENT;
+}
- // if there are no pending events, poll all channels once
- if (ws->polled != NULL && pollcount++ == 0) {
- for (chan = ws->polled;
- chan != NULL && chan->waitset == ws && chan->state == CHAN_POLLED;
- chan = chan->next) {
-
- poll_channel(chan);
- if (ws->pending != NULL) {
- goto recheck;
- }
-
- if (chan->next == ws->polled) { // reached the start of the queue
- break;
- }
- }
- }
+errval_t check_for_event(struct waitset *ws)
+{
+ errval_t err;
- return LIB_ERR_NO_EVENT;
+ assert(ws != NULL);
+ dispatcher_handle_t handle = disp_disable();
+ err = check_for_event_disabled(ws, handle);
+ disp_enable(handle);
+ return err;
}
/**
errval_t event_dispatch_debug(struct waitset *ws)
{
struct event_closure closure;
- errval_t err = get_next_event_debug(ws, &closure, false);
+ struct waitset_chanstate *channel;
+ dispatcher_handle_t handle = disp_disable();
+ errval_t err = get_next_event_disabled(ws, &channel, &closure, NULL, handle,
+ true);
+ disp_enable(handle);
if (err_is_fail(err)) {
return err;
}
assert(closure.handler != NULL);
-// printf("%s: event_dispatch: %p: \n", disp_name(), closure.handler);
-
-
closure.handler(closure.arg);
return SYS_ERR_OK;
}
/**
+ * \brief Dispatch events until a specific event is received
+ *
+ * Wait for events and dispatch them. If a specific event comes, don't call
+ * a closure, just return.
+ *
+ * \param ws Waitset
+ * \param waitfor Event, that we are waiting for
+ * \param error_var Error variable that can be changed by closures
+ */
+
+errval_t wait_for_channel(struct waitset *ws, struct waitset_chanstate *waitfor,
+ errval_t *error_var)
+{
+ assert(waitfor->waitset == ws);
+ for (;;) {
+ struct event_closure closure;
+ struct waitset_chanstate *channel;
+
+ dispatcher_handle_t handle = disp_disable();
+ errval_t err = get_next_event_disabled(ws, &channel, &closure, waitfor,
+ handle, false);
+ disp_enable(handle);
+ if (err_is_fail(err)) {
+ assert(0);
+ return err;
+ }
+ if (channel == waitfor) {
+ return SYS_ERR_OK;
+ }
+ assert(!channel->wait_for);
+ assert(closure.handler != NULL);
+ closure.handler(closure.arg);
+ if (err_is_fail(*error_var))
+ return *error_var;
+ }
+}
+
+/**
* \brief check and dispatch next event on given waitset
*
* Check if there is any pending activity on some channel, or deferred
*/
errval_t event_dispatch_non_block(struct waitset *ws)
{
- assert(ws != NULL);
+ struct waitset_chanstate *channel;
struct event_closure closure;
- errval_t err = check_for_event(ws, &closure);
+ assert(ws != NULL);
+
+ // are there any pending events on the waitset?
+ dispatcher_handle_t handle = disp_disable();
+ errval_t err = check_for_event_disabled(ws, handle);
if (err_is_fail(err)) {
+ disp_enable(handle);
return err;
}
-
+ err = get_next_event_disabled(ws, &channel, &closure, NULL, handle,
+ false);
+ if (err_is_fail(err))
+ return err;
+ disp_enable(handle);
assert(closure.handler != NULL);
closure.handler(closure.arg);
return SYS_ERR_OK;
#ifndef NDEBUG
chan->prev = chan->next = NULL;
#endif
+ chan->persistent = false;
+ chan->token = 0;
+ chan->wait_for = NULL;
}
/**
}
chan->waitset = ws;
+ chan->token = 0;
// channel must not already be registered!
assert_disabled(chan->next == NULL && chan->prev == NULL);
chan->closure = closure;
// enqueue this channel on the waitset's queue of idle channels
- if (ws->idle == NULL) {
- chan->next = chan->prev = chan;
- ws->idle = chan;
- } else {
- chan->next = ws->idle;
- chan->prev = chan->next->prev;
- chan->next->prev = chan;
- chan->prev->next = chan;
- }
+ enqueue(&ws->idle, chan);
chan->state = CHAN_IDLE;
return SYS_ERR_OK;
}
chan->waitset = ws;
+ chan->token = 0;
// channel must not already be registered!
assert_disabled(chan->next == NULL && chan->prev == NULL);
chan->closure = closure;
// enqueue this channel on the waitset's queue of polled channels
- if (ws->polled == NULL) {
- chan->next = chan->prev = chan;
- ws->polled = chan;
- if (ws->waiting_threads != NULL && !ws->polling) {
- // start a blocked thread polling
- ws->polling = true;
- struct thread *t;
- t = thread_unblock_one_disabled(handle, &ws->waiting_threads, NULL);
- assert_disabled(t == NULL); // shouldn't see a remote thread: waitsets are per-dispatcher
- }
- } else {
- chan->next = ws->polled;
- chan->prev = chan->next->prev;
- chan->next->prev = chan;
- chan->prev->next = chan;
- }
+ enqueue(&ws->polled, chan);
chan->state = CHAN_POLLED;
+ enqueue_polled(&get_dispatcher_generic(handle)->polled_channels, chan);
return SYS_ERR_OK;
}
}
/**
- * \brief Mark an idle channel as polled
- *
- * The given channel will periodically have its poll function called.
- * The channel must already be registered.
- *
- * \param chan Waitset's per-channel state
- */
-errval_t waitset_chan_start_polling(struct waitset_chanstate *chan)
-{
- errval_t err = SYS_ERR_OK;
-
- dispatcher_handle_t handle = disp_disable();
-
- struct waitset *ws = chan->waitset;
- if (ws == NULL) {
- err = LIB_ERR_CHAN_NOT_REGISTERED;
- goto out;
- }
-
- assert(chan->state != CHAN_UNREGISTERED);
- if (chan->state != CHAN_IDLE) {
- goto out; // no-op if polled or pending
- }
-
- // remove from idle queue
- if (chan->next == chan) {
- assert(chan->prev == chan);
- assert(ws->idle == chan);
- ws->idle = NULL;
- } else {
- chan->prev->next = chan->next;
- chan->next->prev = chan->prev;
- if (ws->idle == chan) {
- ws->idle = chan->next;
- }
- }
-
- // enqueue on polled queue
- if (ws->polled == NULL) {
- ws->polled = chan;
- chan->next = chan->prev = chan;
- if (ws->waiting_threads != NULL && !ws->polling) {
- // start a blocked thread polling
- ws->polling = true;
- struct thread *t;
- t = thread_unblock_one_disabled(handle, &ws->waiting_threads, NULL);
- assert(t == NULL); // shouldn't see a remote thread: waitsets are per-dispatcher
- }
- } else {
- chan->next = ws->polled;
- chan->prev = ws->polled->prev;
- chan->next->prev = chan;
- chan->prev->next = chan;
- }
- chan->state = CHAN_POLLED;
-
-out:
- disp_enable(handle);
- return err;
-}
-
-/**
- * \brief Stop polling the given channel, making it idle again
- *
- * \param chan Waitset's per-channel state
- */
-errval_t waitset_chan_stop_polling(struct waitset_chanstate *chan)
-{
- errval_t err = SYS_ERR_OK;
-
- dispatcher_handle_t handle = disp_disable();
-
- struct waitset *ws = chan->waitset;
- if (ws == NULL) {
- err = LIB_ERR_CHAN_NOT_REGISTERED;
- goto out;
- }
-
- assert(chan->state != CHAN_UNREGISTERED);
- if (chan->state != CHAN_POLLED) {
- goto out; // no-op if idle or pending
- }
-
- // remove from polled queue
- if (chan->next == chan) {
- assert(chan->prev == chan);
- assert(ws->polled == chan);
- ws->polled = NULL;
- } else {
- chan->prev->next = chan->next;
- chan->next->prev = chan->prev;
- if (ws->polled == chan) {
- ws->polled = chan->next;
- }
- }
-
- // enqueue on idle queue
- if (ws->idle == NULL) {
- ws->idle = chan;
- chan->next = chan->prev = chan;
- } else {
- chan->next = ws->idle;
- chan->prev = ws->idle->prev;
- chan->next->prev = chan;
- chan->prev->next = chan;
- }
- chan->state = CHAN_IDLE;
-
-out:
- disp_enable(handle);
- return err;
-}
-
-/**
* \brief Cancel a previous callback registration
*
* Remove the registration for a callback on the given channel.
*
* \param chan Waitset's per-channel state
*/
-errval_t waitset_chan_deregister_disabled(struct waitset_chanstate *chan)
+errval_t waitset_chan_deregister_disabled(struct waitset_chanstate *chan,
+ dispatcher_handle_t handle)
{
assert_disabled(chan != NULL);
struct waitset *ws = chan->waitset;
chan->waitset = NULL;
assert_disabled(chan->next != NULL && chan->prev != NULL);
- if (chan->next == chan) {
- // only thing in the list: must be the head
- assert_disabled(chan->prev == chan);
- switch (chan->state) {
- case CHAN_IDLE:
- assert_disabled(chan == ws->idle);
- ws->idle = NULL;
- break;
-
- case CHAN_POLLED:
- assert_disabled(chan == ws->polled);
- ws->polled = NULL;
- break;
-
- case CHAN_PENDING:
- assert_disabled(chan == ws->pending);
- ws->pending = NULL;
- break;
+ switch (chan->state) {
+ case CHAN_IDLE:
+ dequeue(&ws->idle, chan);
+ break;
- default:
- assert_disabled(!"invalid channel state in deregister");
- }
- } else {
- assert_disabled(chan->prev != chan);
- chan->prev->next = chan->next;
- chan->next->prev = chan->prev;
- switch (chan->state) {
- case CHAN_IDLE:
- if (chan == ws->idle) {
- ws->idle = chan->next;
- }
- break;
+ case CHAN_POLLED:
+ dequeue(&ws->polled, chan);
+ dequeue_polled(&get_dispatcher_generic(handle)->polled_channels, chan);
+ break;
- case CHAN_POLLED:
- if (chan == ws->polled) {
- ws->polled = chan->next;
- }
- break;
+ case CHAN_PENDING:
+ dequeue(&ws->pending, chan);
+ break;
- case CHAN_PENDING:
- if (chan == ws->pending) {
- ws->pending = chan->next;
- }
- break;
+ case CHAN_WAITING:
+ dequeue(&ws->waiting, chan);
+ break;
- default:
- assert_disabled(!"invalid channel state in deregister");
- }
+ default:
+ assert_disabled(!"invalid channel state in deregister");
}
chan->state = CHAN_UNREGISTERED;
-
-#ifndef NDEBUG
- chan->prev = chan->next = NULL;
-#endif
-
+ chan->wait_for = NULL;
return SYS_ERR_OK;
}
errval_t waitset_chan_deregister(struct waitset_chanstate *chan)
{
dispatcher_handle_t handle = disp_disable();
- errval_t err = waitset_chan_deregister_disabled(chan);
+ errval_t err = waitset_chan_deregister_disabled(chan, handle);
disp_enable(handle);
return err;
}
switch(chan->state) {
case CHAN_IDLE:
- if (chan->next == chan) {
- assert(chan->prev == chan);
- assert(ws->idle == chan);
- ws->idle = NULL;
- } else {
- chan->prev->next = chan->next;
- chan->next->prev = chan->prev;
- if (ws->idle == chan) {
- ws->idle = chan->next;
- }
- }
-
- if (new_ws->idle == NULL) {
- new_ws->idle = chan;
- chan->next = chan->prev = chan;
- } else {
- chan->next = new_ws->idle;
- chan->prev = new_ws->idle->prev;
- chan->next->prev = chan;
- chan->prev->next = chan;
- }
+ dequeue(&ws->idle, chan);
+ enqueue(&new_ws->idle, chan);
break;
case CHAN_POLLED:
- if (chan->next == chan) {
- assert(chan->prev == chan);
- assert(ws->polled == chan);
- ws->polled = NULL;
- } else {
- chan->prev->next = chan->next;
- chan->next->prev = chan->prev;
- if (ws->polled == chan) {
- ws->polled = chan->next;
- }
- }
-
- if (new_ws->polled == NULL) {
- new_ws->polled = chan;
- chan->next = chan->prev = chan;
- } else {
- chan->next = new_ws->polled;
- chan->prev = new_ws->polled->prev;
- chan->next->prev = chan;
- chan->prev->next = chan;
- }
+ dequeue(&ws->polled, chan);
+ enqueue(&new_ws->polled, chan);
break;
case CHAN_PENDING:
- if (chan->next == chan) {
- assert(chan->prev == chan);
- assert(ws->pending == chan);
- ws->pending = NULL;
- } else {
- chan->prev->next = chan->next;
- chan->next->prev = chan->prev;
- if (ws->pending == chan) {
- ws->pending = chan->next;
- }
- }
+ dequeue(&ws->pending, chan);
+ enqueue(&new_ws->pending, chan);
+ break;
- if (new_ws->pending == NULL) {
- new_ws->pending = chan;
- chan->next = chan->prev = chan;
- } else {
- chan->next = new_ws->pending;
- chan->prev = new_ws->pending->prev;
- chan->next->prev = chan;
- chan->prev->next = chan;
- }
+ case CHAN_WAITING:
+ dequeue(&ws->waiting, chan);
+ enqueue(&new_ws->waiting, chan);
break;
case CHAN_UNREGISTERED:
}
// remove from previous queue (either idle or polled)
- if (chan->next == chan) {
- assert_disabled(chan->prev == chan);
- if (chan->state == CHAN_IDLE) {
- assert_disabled(ws->idle == chan);
- ws->idle = NULL;
- } else {
- assert_disabled(chan->state == CHAN_POLLED);
- assert_disabled(ws->polled == chan);
- ws->polled = NULL;
- }
+ if (chan->state == CHAN_IDLE) {
+ dequeue(&ws->idle, chan);
} else {
- chan->prev->next = chan->next;
- chan->next->prev = chan->prev;
- if (chan->state == CHAN_IDLE) {
- if (ws->idle == chan) {
- ws->idle = chan->next;
- }
- } else {
- assert_disabled(chan->state == CHAN_POLLED);
- if (ws->polled == chan) {
- ws->polled = chan->next;
- }
- }
+ assert_disabled(chan->state == CHAN_POLLED);
+ dequeue(&ws->polled, chan);
+ dequeue_polled(&get_dispatcher_generic(handle)->polled_channels, chan);
}
+ // else mark channel pending and move to end of pending event queue
+ enqueue(&ws->pending, chan);
+ chan->state = CHAN_PENDING;
+
// is there a thread blocked on this waitset? if so, awaken it with the event
- if (ws->waiting_threads != NULL) {
- chan->waitset = NULL;
-#ifndef NDEBUG
- chan->prev = chan->next = NULL;
-#endif
- chan->state = CHAN_UNREGISTERED;
+ struct thread *thread = find_recipient(ws, chan, thread_self());
+ if (thread) {
struct thread *t;
+ ws->waiting_threads = thread;
t = thread_unblock_one_disabled(handle, &ws->waiting_threads, chan);
assert_disabled(t == NULL);
- return SYS_ERR_OK;
- }
-
- // else mark channel pending and move to end of pending event queue
- chan->state = CHAN_PENDING;
- if (ws->pending == NULL) {
- ws->pending = chan;
- chan->next = chan->prev = chan;
- } else {
- chan->next = ws->pending;
- chan->prev = ws->pending->prev;
- assert_disabled(ws->pending->next != NULL);
- assert_disabled(ws->pending->prev != NULL);
- assert_disabled(chan->prev != NULL);
- chan->next->prev = chan;
- chan->prev->next = chan;
}
-
return SYS_ERR_OK;
}
*/
errval_t waitset_chan_trigger(struct waitset_chanstate *chan)
{
- dispatcher_handle_t disp = disp_disable();
- errval_t err = waitset_chan_trigger_disabled(chan, disp);
- disp_enable(disp);
+ dispatcher_handle_t handle = disp_disable();
+ errval_t err = waitset_chan_trigger_disabled(chan, handle);
+ disp_enable(handle);
return err;
}
// set closure
chan->closure = closure;
+ // mark channel pending and place on end of pending event queue
+ chan->waitset = ws;
+ enqueue(&ws->pending, chan);
+ // if (first)
+ // ws->pending = chan;
+ chan->state = CHAN_PENDING;
+
// is there a thread blocked on this waitset? if so, awaken it with the event
- if (ws->waiting_threads != NULL) {
+ struct thread *thread = find_recipient(ws, chan, thread_self());
+ if (thread) {
struct thread *t;
+ ws->waiting_threads = thread;
t = thread_unblock_one_disabled(handle, &ws->waiting_threads, chan);
assert_disabled(t == NULL);
- return SYS_ERR_OK;
- }
-
- // mark channel pending and place on end of pending event queue
- chan->waitset = ws;
- chan->state = CHAN_PENDING;
- if (ws->pending == NULL) {
- ws->pending = chan;
- chan->next = chan->prev = chan;
- } else {
- chan->next = ws->pending;
- chan->prev = ws->pending->prev;
- chan->next->prev = chan;
- chan->prev->next = chan;
}
-
- assert(ws->pending->prev != NULL && ws->pending->next != NULL);
-
return SYS_ERR_OK;
}
p += p->s.size;
p->s.size = nunits;
}
+ p->s.magic = 0xdeadbeef;
state->header_freep = prevp;
#ifdef CONFIG_MALLOC_DEBUG
{
assert((lvaddr_t)ap >= base && (lvaddr_t)ap < limit);
#endif
+ if (((Header *)ap)[-1].s.magic != 0xdeadbeef) {
+ debug_printf("%s: Trying to free not malloced region: %p\n", __func__, ap);
+ return;
+ }
+ ((Header *)ap)[-1].s.magic = 0;
MALLOC_LOCK;
__free_locked(ap);
lesscore();
{
errval_t err;
errval_t exist_err;
- char* record = NULL;
char** names = NULL;
uint64_t mode = 0;
- uint64_t state = 0;
- uint64_t fn = 0;
octopus_trigger_id_t tid;
size_t current_barriers = 0;
octopus_trigger_t t = oct_mktrigger(OCT_ERR_NO_RECORD, octopus_BINDING_RPC,
err = oct_set_get(SET_SEQUENTIAL, barrier_record,
"%s_ { barrier: '%s' }", name, name);
+ *barrier_record = strdup(*barrier_record);
+ if (*barrier_record == NULL) {
+ return LIB_ERR_MALLOC_FAIL;
+ }
err = oct_get_names(&names, ¤t_barriers, "_ { barrier: '%s' }",
name);
oct_free_names(names, current_barriers);
}
if (err_no(err) == OCT_ERR_NO_RECORD) {
// Wait until barrier record is created
- err = cl->recv.trigger(cl, &tid, &fn, &mode, &record, &state);
- free(record);
+ err = cl->recv.trigger(cl, NULL, NULL, &mode, NULL, NULL);
assert(mode & OCT_REMOVED);
err = SYS_ERR_OK;
errval_t err;
char* rec_name = NULL;
char* barrier_name = NULL;
- char* record = NULL;
char** names = NULL;
size_t remaining_barriers = 0;
uint64_t mode = 0;
- uint64_t state = 0;
- uint64_t fn = 0;
octopus_trigger_id_t tid;
octopus_trigger_t t = oct_mktrigger(SYS_ERR_OK, octopus_BINDING_RPC,
OCT_ON_DEL, NULL, NULL);
if (err_is_ok(err)) {
// Wait until everyone has left the barrier
- err = cl->recv.trigger(cl, &tid, &fn, &mode, &record, &state);
+ err = cl->recv.trigger(cl, NULL, NULL, &mode, NULL, NULL);
assert(mode & OCT_REMOVED);
}
else if (err_no(err) == OCT_ERR_NO_RECORD) {
}
out:
- free(record);
free(rec_name);
free(barrier_name);
return err;
errval_t err = SYS_ERR_OK;
va_list args;
- char* data = NULL;
char* buf = NULL;
*len = 0;
struct octopus_thc_client_binding_t* cl = oct_get_thc_client();
- errval_t error_code;
- octopus_trigger_id_t tid;
- err = cl->call_seq.get_names(cl, buf, NOP_TRIGGER, &data,
- &tid, &error_code);
+ struct octopus_get_names_response__rx_args reply;
+ err = cl->call_seq.get_names(cl, buf, NOP_TRIGGER, reply.output,
+ &reply.tid, &reply.error_code);
if (err_is_ok(err)) {
- err = error_code;
+ err = reply.error_code;
}
if (err_is_ok(err)) {
- err = oct_parse_names(data, names, len);
+ err = oct_parse_names(reply.output, names, len);
//qsort(*names, *len, sizeof(char*), cmpstringp);
}
free(buf);
- free(data);
return err;
}
errval_t oct_get(char** data, const char* query, ...)
{
assert(query != NULL);
- errval_t error_code;
errval_t err = SYS_ERR_OK;
- octopus_trigger_id_t tid;
va_list args;
char* buf = NULL;
struct octopus_thc_client_binding_t* cl = oct_get_thc_client();
assert(cl != NULL);
- err = cl->call_seq.get(cl, buf, NOP_TRIGGER, data,
- &tid, &error_code);
+
+ struct octopus_get_response__rx_args reply;
+ err = cl->call_seq.get(cl, buf, NOP_TRIGGER, reply.output,
+ &reply.tid, &reply.error_code);
if (err_is_ok(err)) {
- err = error_code;
+ err = reply.error_code;
}
free(buf);
+
+ if (err_is_fail(err)) {
+ return err;
+ }
+
+ if (data) {
+ *data = strdup(reply.output);
+ }
+
+
return err;
}
// Send to Server
struct octopus_thc_client_binding_t* cl = oct_get_thc_client();
- char* record = NULL;
errval_t error_code;
- octopus_trigger_id_t tid;
- err = cl->call_seq.set(cl, buf, SET_DEFAULT, NOP_TRIGGER, false,
- &record, &tid, &error_code);
- assert(record == NULL);
+ err = cl->call_seq.set(cl, buf, SET_DEFAULT, NOP_TRIGGER, false, NULL, NULL,
+ &error_code);
if (err_is_ok(err)) {
err = error_code;
// Send to Server
struct octopus_thc_client_binding_t* cl = oct_get_thc_client();
- char* record = NULL;
errval_t error_code;
- octopus_trigger_id_t tid;
- err = cl->call_seq.set(cl, buf, mode, NOP_TRIGGER, false,
- &record, &tid, &error_code);
- assert(record == NULL);
+ err = cl->call_seq.set(cl, buf, mode, NOP_TRIGGER, false, NULL, NULL,
+ &error_code);
if (err_is_ok(err)) {
err = error_code;
// Send to Server
struct octopus_thc_client_binding_t* cl = oct_get_thc_client();
- errval_t error_code;
- octopus_trigger_id_t tid;
- err = cl->call_seq.set(cl, buf, mode, NOP_TRIGGER, true, record,
- &tid, &error_code);
+ struct octopus_set_response__rx_args reply;
+ err = cl->call_seq.set(cl, buf, mode, NOP_TRIGGER, true, reply.record,
+ &reply.tid, &reply.error_code);
if (err_is_ok(err)) {
- err = error_code;
+ err = reply.error_code;
}
free(buf);
+
+ if (err_is_fail(err)) {
+ return err;
+ }
+
+ if (record) {
+ *record = strdup(reply.record);
+ }
+
return err;
}
errval_t oct_get_with_idcap(char **data, struct capref idcap)
{
assert(!capref_is_null(idcap));
- errval_t error_code;
errval_t err = SYS_ERR_OK;
- octopus_trigger_id_t tid;
struct octopus_thc_client_binding_t *cl = oct_get_thc_client();
assert(cl != NULL);
- err = cl->call_seq.get_with_idcap(cl, idcap, NOP_TRIGGER, data, &tid,
- &error_code);
+ struct octopus_get_with_idcap_response__rx_args reply;
+ err = cl->call_seq.get_with_idcap(cl, idcap, NOP_TRIGGER, reply.output,
+ &reply.tid, &reply.error_code);
if (err_is_ok(err)) {
- err = error_code;
+ err = reply.error_code;
+ }
+
+ if (err_is_fail(err)) {
+ return err;
+ }
+
+ if (data) {
+ *data = strdup(reply.output);
}
return err;
// Send to Server
struct octopus_thc_client_binding_t *cl = oct_get_thc_client();
- char *record = NULL;
errval_t error_code;
- octopus_trigger_id_t tid;
err = cl->call_seq.set_with_idcap(cl, idcap, buf, SET_DEFAULT, NOP_TRIGGER,
- false, &record, &tid, &error_code);
- assert(record == NULL);
+ false, NULL, NULL, &error_code);
if (err_is_ok(err)) {
err = error_code;
struct octopus_thc_client_binding_t* cl = oct_get_thc_client();
errval_t error_code;
- octopus_trigger_id_t tid;
- err = cl->call_seq.del(cl, buf, NOP_TRIGGER, &tid, &error_code);
+ err = cl->call_seq.del(cl, buf, NOP_TRIGGER, NULL, &error_code);
if (err_is_ok(err)) {
err = error_code;
}
struct octopus_thc_client_binding_t* cl = oct_get_thc_client();
errval_t error_code;
- octopus_trigger_id_t tid;
- err = cl->call_seq.exists(cl, buf, NOP_TRIGGER, &tid, &error_code);
+ err = cl->call_seq.exists(cl, buf, NOP_TRIGGER, NULL, &error_code);
if (err_is_ok(err)) {
err = error_code;
}
struct octopus_thc_client_binding_t* cl = oct_get_thc_client();
- errval_t error_code;
- err = cl->call_seq.wait_for(cl, buf, record, &error_code);
+ struct octopus_wait_for_response__rx_args reply;
+ err = cl->call_seq.wait_for(cl, buf, reply.record, &reply.error_code);
+ if (err_is_fail(err)) {
+ goto out;
+ }
+ err = reply.error_code;
+
if (err_is_fail(err)) {
goto out;
}
- err = error_code;
+
+ if (record) {
+ *record = strdup(reply.record);
+ }
out:
free(buf);
errval_t err = SYS_ERR_OK;
errval_t exist_err;
char** names = NULL;
- char* record = NULL;
char* name = NULL;
size_t len = 0;
size_t i = 0;
bool found = false;
uint64_t mode = 0;
- uint64_t state = 0;
- uint64_t fn = 0;
octopus_trigger_id_t tid;
octopus_trigger_t t = oct_mktrigger(SYS_ERR_OK, octopus_BINDING_RPC,
OCT_ON_DEL, NULL, NULL);
if (err_is_fail(err)) {
goto out;
}
+ /// XXX why is there a strdup ?
+ *lock_record = strdup(*lock_record);
err = oct_read(*lock_record, "%s", &name);
if (err_is_fail(err)) {
goto out;
}
if (err_is_ok(exist_err)) {
- err = cl->recv.trigger(cl, &tid, &fn, &mode, &record, &state);
+ err = cl->recv.trigger(cl, &tid, NULL, &mode, NULL, NULL);
assert(err_is_ok(err));
- free(record);
assert(mode & OCT_REMOVED);
}
else if (err_no(exist_err) != OCT_ERR_NO_RECORD) {
else {
fprintf(stderr, "Incoming subscription(%"PRIu64") for %s with unset handler function.",
id, record);
- free(record);
}
}
errval_t oct_sem_wait(uint32_t id)
{
errval_t err = SYS_ERR_OK;
- char* result = NULL;
- octopus_trigger_id_t tid;
octopus_trigger_t t = oct_mktrigger(OCT_ERR_NO_RECORD,
octopus_BINDING_RPC, OCT_ON_SET, NULL, NULL);
struct octopus_thc_client_binding_t* cl = oct_get_thc_client();
// XXX: The current implementation suffers from a herd effect,
// may be worth it to use locks for this critical section
while (1) {
- cl->call_seq.get(cl, query, t, &result, &tid, &err);
+ struct octopus_get_response__rx_args reply;
+ cl->call_seq.get(cl, query, t, reply.output, &reply.tid, &err);
if (err_is_ok(err)) {
- errval_t del_err = oct_del(result);
- free(result);
- result = NULL;
+ errval_t del_err = oct_del(reply.output);
if (err_is_ok(del_err)) {
break; // Decreased successfully
}
else if (err_no(err) == OCT_ERR_NO_RECORD) {
// No record found, wait until one is posted
- char* trigger_result = NULL;
- uint64_t fn, mode, state;
- cl->recv.trigger(cl, &tid, &fn, &mode, &trigger_result, &state);
- free(trigger_result);
+ cl->recv.trigger(cl, NULL, NULL, NULL, NULL, NULL);
}
else {
break; // Unexpected error
}
}
- free(result);
return err;
}
else {
fprintf(stderr, "Incoming trigger(%"PRIu64") for %s with unset handler function.",
id, record);
- free(record);
}
}
trigger_handler_fn event_handler, void* state,
octopus_trigger_id_t* tid)
{
- errval_t error_code;
char** names = NULL;
- char* output = NULL;
char* record = NULL; // freed by cpu_change_event
size_t len = 0;
octopus_trigger_t t = oct_mktrigger(0, octopus_BINDING_EVENT,
// Get current cores registered in system
struct octopus_thc_client_binding_t* rpc = oct_get_thc_client();
+
+ struct octopus_get_names_response__rx_args reply;
errval_t err = rpc->call_seq.get_names(rpc, query,
- t, &output, tid, &error_code);
+ t, reply.output, &reply.tid, &reply.error_code);
if (err_is_fail(err)) {
goto out;
}
- err = error_code;
+ err = reply.error_code;
switch(err_no(err)) {
case SYS_ERR_OK:
- err = oct_parse_names(output, &names, &len);
+ err = oct_parse_names(reply.output, &names, &len);
if (err_is_fail(err)) {
goto out;
}
break;
case OCT_ERR_NO_RECORD:
- assert(record == NULL);
break;
default:
DEBUG_ERR(err, "Unable to retrieve core record for %s", names[i]);
- assert(record == NULL);
break;
}
}
out:
oct_free_names(names, len);
- free(output);
return err;
}
ns->cap = cap;
ns->error = reterr;
ns->reply(b, ns);
-
- free(key);
}
static void put_cap_reply(struct octopus_binding *b,
reterr = OCT_ERR_CAP_OVERWRITE;
err = cap_delete(cap);
assert(err_is_ok(err));
- free(key);
} else {
+ /* we need to make our own copy of the key */
+ key = strdup(key);
int r = capdb->d.put_capability(&capdb->d, key, cap);
assert(r == 0);
}
assert(err_is_ok(err));
ns->error = reterr;
ns->reply(b, ns);
-
- free(key);
}
errval_t init_capstorage(void)
drs->reply(b, drs);
free_ast(ast);
- free(query);
}
static void get_names_reply(struct octopus_binding* b,
drs->reply(b, drs);
free_ast(ast);
- free(query);
}
static void set_reply(struct octopus_binding* b, struct oct_reply_state* drs)
drs->reply(b, drs);
free_ast(ast);
- free(query);
}
static errval_t build_query_with_idcap(char **query_p, struct capref idcap,
drs->reply(b, drs);
free_ast(ast);
- free(attributes);
if (query != NULL) {
free(query);
}
drs->reply(b, drs);
free_ast(ast);
- free(query);
}
static void exists_reply(struct octopus_binding* b, struct oct_reply_state* drs)
drs->reply(b, drs);
free_ast(ast);
- free(query);
}
static void wait_for_reply(struct octopus_binding* b, struct oct_reply_state* drs)
if (err_is_ok(err)) {
err = get_record(ast, &drs->query_state);
if (err_no(err) == OCT_ERR_NO_RECORD) {
- debug_printf("waiting for: %s\n", query);
uint64_t wid;
set_watch_err = set_watch(b, ast, OCT_ON_SET, drs, &wid);
}
}
free_ast(ast);
- free(query);
}
static void subscribe_reply(struct octopus_binding* b,
drs->reply(b, drs);
free_ast(ast);
- free(query);
}
static void unsubscribe_reply(struct octopus_binding* b,
out2:
free_ast(ast);
out1:
- free(record);
+ return;
}
void get_identifier(struct octopus_binding* b)
interrupt_handler_fn reloc_handler,
void *reloc_handler_arg)
{
- pci_caps_per_bar_t *caps_per_bar = NULL;
+ pci_caps_per_bar_t caps_per_bar;
uint8_t nbars;
errval_t err, msgerr;
err = pci_client->vtbl.
init_pci_device(pci_client, class, subclass, prog_if, vendor,
device, bus, dev, fun, &msgerr,
- &nbars, &caps_per_bar);
+ &nbars, caps_per_bar, caps_per_bar + 1, caps_per_bar + 2,
+ caps_per_bar + 3, caps_per_bar + 4, caps_per_bar + 5);
if (err_is_fail(err)) {
return err;
} else if (err_is_fail(msgerr)) {
- free(caps_per_bar);
return msgerr;
}
for (int nb = 0; nb < nbars; nb++) {
struct device_mem *bar = &bars[nb];
- int ncaps = (*caps_per_bar)[nb];
+ int ncaps = (caps_per_bar)[nb];
if (ncaps != 0) {
bar->nr_caps = ncaps;
bar->frame_cap = malloc(ncaps * sizeof(struct capref)); // FIXME: leak
err = SYS_ERR_OK;
out:
- free(caps_per_bar);
return err;
}
}
strncpy(dir->dirent.d_name, name, sizeof(dir->dirent.d_name));
- free(name);
dir->dirent.d_name[sizeof(dir->dirent.d_name) - 1] = '\0';
return &dir->dirent;
}
static errval_t allocate_unique_number(uint32_t *np)
{
errval_t err;
- char *record;
- octopus_trigger_id_t tid;
struct octopus_rpc_client *oc = get_octopus_rpc_client();
+ struct octopus_set_response__rx_args reply;
+
/* request a system-wide unique number at octopus */
char *query = PTY_PTS_OCTOPUS_PREFIX;
- oc->vtbl.set(oc, query, SET_SEQUENTIAL, NOP_TRIGGER, true, &record, &tid,
- &err);
+ oc->vtbl.set(oc, query, SET_SEQUENTIAL, NOP_TRIGGER, true, reply.record,
+ &reply.tid, &err);
if (err_is_fail(err)) {
goto finish;
}
* Octpus returns the record in the form 'ptypts0 {}'. Extract unique
* number.
*/
- int ret = sscanf(record, PTY_PTS_OCTOPUS_PREFIX "%" PRIu32, np);
+ int ret = sscanf(reply.record, PTY_PTS_OCTOPUS_PREFIX "%" PRIu32, np);
assert(ret == 1);
finish:
- free(record);
return err;
}
}
/* ------------------------- evaluate ------------------------------ */
-errval_t skb_evaluate(char *query, char **result, char **str_error, int32_t *int_error)
+errval_t skb_evaluate(char *query, char **ret_result, char **ret_str_error, int32_t *int_error)
{
errval_t err;
struct skb_state *skb_state = get_skb_state();
- err = skb_state->skb->vtbl.run(skb_state->skb, query, result, str_error,
- int_error);
+ // allocate memory for holding the response data
+ char *result = NULL;
+ if (ret_result) {
+ result = malloc(skb__run_response_output_MAX_ARGUMENT_SIZE);
+ if (result == NULL) {
+ return LIB_ERR_MALLOC_FAIL;
+ }
+ }
+ char *str_error = NULL;
+ if (ret_str_error) {
+ str_error = malloc(skb__run_response_str_error_MAX_ARGUMENT_SIZE);
+ if (str_error == NULL) {
+ if (result) {
+ free(result);
+ }
+ return LIB_ERR_MALLOC_FAIL;
+ }
+ }
+ err = skb_state->skb->vtbl.run(skb_state->skb, query, result,
+ str_error, int_error);
if (err_is_fail(err)) {
+ if (result) {
+ free(result);
+ }
+ if (str_error) {
+ free(str_error);
+ }
return err_push(err, SKB_ERR_RUN);
}
+
+ if (ret_result) {
+ *ret_result = result;
+ }
+ if (ret_str_error) {
+ *ret_str_error = str_error;
+ }
+
return SYS_ERR_OK;
}
#include <string.h>
#include <barrelfish/barrelfish.h>
#include <skb/skb.h>
+#include <if/skb_rpcclient_defs.h>
+#include <barrelfish/core_state_arch.h>
#include "skb_debug.h"
-#define BUFFER_SIZE SKB_REPLY_BUF_SIZE
-#define OUTPUT_SIZE SKB_REPLY_BUF_SIZE
+#define BUFFER_SIZE skb__run_call_input_MAX_ARGUMENT_SIZE
+#define OUTPUT_SIZE skb__run_response_output_MAX_ARGUMENT_SIZE
/* XXX: The following static chars make the skb connection not thread
safe and we probably don't want to put them in the per dispatcher
corestate as they are so big. */
-static char buffer[BUFFER_SIZE];
-static char output[OUTPUT_SIZE];
-static char error_output[OUTPUT_SIZE];
+static char buffer[skb__run_call_input_MAX_ARGUMENT_SIZE + 1];
+static char output[skb__run_response_output_MAX_ARGUMENT_SIZE + 1];
+static char error_output[skb__run_response_str_error_MAX_ARGUMENT_SIZE + 1];
static int error_code;
int skb_read_error_code(void)
errval_t skb_execute(char *goal)
{
- int32_t error;
- char *result, *error_out;
- errval_t err = skb_evaluate(goal, &result, &error_out, &error);
+ errval_t err;
+ struct skb_state *skb_state = get_skb_state();
+
+ err = skb_state->skb->vtbl.run(skb_state->skb, goal, output,
+ error_output, &error_code);
if (err_is_fail(err)) {
- return err_push(err, SKB_ERR_EVALUATE);
+ return err_push(err, SKB_ERR_RUN);
}
- error_code = error;
- strncpy(output, result, OUTPUT_SIZE);
- strncpy(error_output, error_out, OUTPUT_SIZE);
- free(result);
- free(error_out);
- if (error != 0) {
+
+ if (error_code != 0) {
return err_push(err, SKB_ERR_EXECUTION);
}
+
return err;
}
}
}
- char* record = NULL;
- octopus_trigger_id_t tid;
- errval_t error_code;
+ struct octopus_get_response__rx_args reply;
err = r->vtbl.get(r, omp_entry, NOP_TRIGGER,
- &record, &tid, &error_code);
+ reply.output, &reply.tid, &reply.error_code);
if (err_is_fail(err)) {
goto out;
}
- err = error_code;
+ err = reply.error_code;
if (err_is_fail(err)) {
if (err_no(err) == OCT_ERR_NO_RECORD) {
err = err_push(err, LIB_ERR_NAMESERVICE_UNKNOWN_NAME);
uint64_t addr = 0;
char *symname = NULL;
- err = oct_read(record, "_ { sym: %s, addr: %d }", &symname, &addr);
+ err = oct_read(reply.output, "_ { sym: %s, addr: %d }", &symname, &addr);
if (err_is_fail(err) || symname == NULL) {
err = err_push(err, LIB_ERR_NAMESERVICE_INVALID_NAME);
goto out;
*ret_name = strdup(symname);
}
- out: free(record);
+ out:
free(omp_entry);
return err;
}
}
}
- char* ret = NULL;
octopus_trigger_id_t tid;
errval_t error_code;
err = r->vtbl.set(r, record, 0, NOP_TRIGGER,
- 0, &ret, &tid, &error_code);
+ 0, NULL, &tid, &error_code);
if (err_is_fail(err)) {
goto out;
}
err = error_code;
out:
- free(record);
-
+ free(record);
return err;
}
}
/* Make a copy of characters, since the output filters might modify them. */
- outdata = malloc(length);
- assert(outdata != NULL);
- memcpy(outdata, data, length);
+ outdata = memdup(data, length);
/* tell user how much we've written (before applying filters) */
*written = length;
term_filter_id_t id = term_client_add_input_filter(client, term_filter_cr2lf);
client->cr2lf_id = id;
}
-
+
return SYS_ERR_OK;
}
break;
}
-errval_t term_client_blocking_tcgetattr(struct term_client *client,
+errval_t term_client_blocking_tcgetattr(struct term_client *client,
struct termios* t)
{
if (client->cr2lf_id > 0) {
return SYS_ERR_OK;
}
-errval_t term_client_blocking_tcsetattr(struct term_client *client,
+errval_t term_client_blocking_tcsetattr(struct term_client *client,
const struct termios* t)
{
errval_t err = term_client_blocking_config(client, TerminalConfig_ECHO, (t->c_lflag & ECHO) > 0);
struct octopus_rpc_client *r = get_octopus_rpc_client();
assert(r != NULL);
- char *record;
- errval_t error_code;
- octopus_trigger_id_t tid;
- err = r->vtbl.get_with_idcap(r, session_id, NOP_TRIGGER, &record, &tid,
- &error_code);
+ struct octopus_get_with_idcap_response__rx_args reply;
+
+ err = r->vtbl.get_with_idcap(r, session_id, NOP_TRIGGER, reply.output, &reply.tid,
+ &reply.error_code);
if (err_is_fail(err)) {
err_push(err, TERM_ERR_LOOKUP_SESSION_RECORD);
goto out;
}
- err = error_code;
+ err = reply.error_code;
if (err_is_fail(err)) {
err_push(err, TERM_ERR_LOOKUP_SESSION_RECORD);
goto out;
int64_t conf_oct;
// oct_read can only parse 64-bit values, we need to parse the irefs as 64bit
// then cast to 32bit
- err = oct_read(record, "_ { session_iref: %d, in_iref: %d, out_iref: %d, "
+ err = oct_read(reply.output, "_ { session_iref: %d, in_iref: %d, out_iref: %d, "
"conf_iref: %d }", &session_oct, &in_oct, &out_oct,
&conf_oct);
//iref_t session_iref = (iref_t)session_oct;
"\n", *in_iref, *out_iref, *conf_iref);
out:
- free(record);
return err;
}
* Make a copy of the data, since the echo filters might modify it and the
* modification should not be seen by the application.
*/
- echodata = malloc(length);
- assert(echodata != NULL);
- memcpy(echodata, data, length);
+ echodata = memdup(data, length);
/* apply echo filters */
term_filter_apply(client->echo_filters, &echodata, &length);
{
struct term_client *client = b->st;
+
+ char *my_data = memdup(data, length);
+
if (client->non_blocking_read) {
assert(client->chars_cb != NULL);
/* handle triggers */
- handle_triggers(client, data, length);
+ handle_triggers(client, my_data, length);
/* filter input */
- term_filter_apply(client->input_filters, &data, &length);
+ term_filter_apply(client->input_filters, &my_data, &length);
/* call user supplied chars_cb */
- client->chars_cb(client->st, data, length);
+ client->chars_cb(client->st, my_data, length);
} else {
assert(client->readbuf == NULL);
- client->readbuf = data;
- client->readbuf_pos = data;
+ client->readbuf = my_data;
+ client->readbuf_pos = my_data;
client->readbuf_len = length;
}
}
uint32_t ret_status;
- uint8_t *tmp;
+ uint8_t tmp[2048];
size_t length;
/* connect with the USB Manager */
err = usb_manager.vtbl.connect(&usb_manager, usb_driver_iref, init_config,
- &ret_status, &tmp, &length);
+ &ret_status, tmp, &length);
if (((usb_error_t) ret_status) != USB_ERR_OK) {
debug_printf("libusb: ERROR connecting to the USB manager\n");
/*
* initialize the devices with the descriptors
- * Do not free the tmp, since the data is still used by the descriptors
*/
usb_device_init(tmp);
{\r
errval_t err;\r
uint32_t ret_status = 0;\r
- uint8_t *data = NULL;\r
+ uint8_t data[2048];\r
size_t length = 0;\r
usb_error_t ret;\r
\r
USB_DEBUG_IDC("libusb: usb_do_request_read()\n");\r
\r
err = usb_manager.vtbl.request_read(&usb_manager, (uint8_t*) req,\r
- sizeof(*req), (uint8_t **) &data, &length, &ret_status);\r
+ sizeof(*req), data, &length, &ret_status);\r
\r
*ret_length = length;\r
\r
\r
USB_DEBUG_IDC("libusb: usb_do_request_read() got data (len=%i)\n", *ret_length);\r
\r
- *ret_data = (void *) data;\r
+ *ret_data = memdup(data, sizeof(data));\r
\r
return (ret);\r
}\r
ahci_mgmt_bound = true;
- // populate list
- uint8_t *port_ids;
- size_t len;
-
- err = ahci_mgmt_rpc.vtbl.list(&ahci_mgmt_rpc, &port_ids, &len);
+ struct ahci_mgmt_list_response__rx_args reply;
+ err = ahci_mgmt_rpc.vtbl.list(&ahci_mgmt_rpc, reply.port_ids, &reply.len);
assert(err_is_ok(err));
- for (size_t i = 0; i < len; i++) {
- uint8_t *data;
- size_t identifylen = 0;
+ for (size_t i = 0; i < reply.len; i++) {
+ struct ahci_mgmt_identify_response__rx_args identify_reply;
err = ahci_mgmt_rpc.vtbl.identify(&ahci_mgmt_rpc,
- port_ids[i], &data, &identifylen);
+ reply.port_ids[i], identify_reply.identify_data,
+ &identify_reply.data_len);
assert(err_is_ok(err));
- assert(identifylen == 512);
+ assert(identify_reply.data_len == 512);
ata_identify_t identify;
- ata_identify_initialize(&identify, (void *)data);
+ ata_identify_initialize(&identify, (void *)identify_reply.identify_data );
//char buf[8192];
//ata_identify_pr(buf, 8192, &identify);
port_ids[i], sectors, sector_size);
struct ahci_handle *handle = calloc(1, sizeof(struct ahci_handle));
- handle->port_num = port_ids[i];
+ handle->port_num = reply.port_ids[i];
struct blockdev_entry *newentry = calloc(1, sizeof(struct blockdev_entry));
newentry->open = false;
//VFS_BLK_DEBUG("bdfs_ahci: read begin: %zu -> %zu\n", bytes, aligned_bytes);
- uint8_t *data;
err = h->ata_rw28_rpc.vtbl.read_dma(&h->ata_rw28_rpc,
- aligned_bytes, blockpos, &data, bytes_read);
- memcpy(buffer, data, *bytes_read);
- free(data);
+ aligned_bytes, blockpos, buffer, bytes_read);
return err;
}
ahci_mgmt_bound = true;
// populate list
- uint8_t *port_ids;
- size_t len;
-
- err = ahci_mgmt_rpc.vtbl.list(&ahci_mgmt_rpc, &port_ids, &len);
+ struct ahci_mgmt_list_response__rx_args reply;
+ err = ahci_mgmt_rpc.vtbl.list(&ahci_mgmt_rpc, reply.port_ids, &reply.len);
assert(err_is_ok(err));
- for (size_t i = 0; i < len; i++) {
+ for (size_t i = 0; i < reply.len; i++) {
if (i > 9) {
break;
}
- uint8_t *data;
- size_t identifylen = 0;
- err = ahci_mgmt_rpc.vtbl.identify(&ahci_mgmt_rpc,
- port_ids[i], &data, &identifylen);
+ struct ahci_mgmt_identify_response__rx_args identify_reply;
+ err = ahci_mgmt_rpc.vtbl.identify(&ahci_mgmt_rpc, reply.port_ids[i],
+ identify_reply.identify_data,
+ &identify_reply.data_len);
assert(err_is_ok(err));
- assert(identifylen == 512);
+ assert(identify_reply.data_len == 512);
ata_identify_t identify;
- ata_identify_initialize(&identify, (void *)data);
+ ata_identify_initialize(&identify, (void *)identify_reply.identify_data);
//char buf[8192];
//ata_identify_pr(buf, 8192, &identify);
port_ids[i], sectors, sector_size);
struct ata_handle *handle = calloc(1, sizeof(struct ata_handle));
- handle->port_num = port_ids[i];
+ handle->port_num = reply.port_ids[i];
struct blockdev_entry *newentry = calloc(1, sizeof(struct blockdev_entry));
newentry->open = false;
}
else if (err == FS_CACHE_NOTPRESENT) {
size_t read_size;
+ data_ = malloc(size);
err = mount->ata_rw28_rpc.vtbl.read_dma(&mount->ata_rw28_rpc,
- size, block, &data_, &read_size);
+ size, block, data_, &read_size);
if (err_is_fail(err)) {
return err;
}
FAT_DEBUG("ata_rw28 initialized.\n");
#endif
-
- // read data from fat boot sector
- uint8_t *data;
size_t size;
+ // read data from fat boot sector
+ uint8_t *data = malloc(ata_rw28__read_dma_block_response_buffer_MAX_ARGUMENT_SIZE);
err = mount->ata_rw28_rpc.vtbl.read_dma_block(&mount->ata_rw28_rpc,
- mount->startblock, &data, &size);
+ mount->startblock, mount->bootsec_data, &size);
if (err_is_fail(err)) {
goto bootsec_read_failed;
}
}
FAT_DEBUG("end sector 0 dump");
#endif
- memcpy(mount->bootsec_data, data, size);
- free(data);
+
data = NULL;
if (memcmp(mount->bootsec_data+0x1FE, "\x55\xAA", 2) != 0) {
mount->block_count);
goto fs_check_failed;
}
+ struct ata_rw28_read_dma_block_response__rx_args reply;
mount->ata_rw28_rpc.vtbl.read_dma_block(&mount->ata_rw28_rpc,
- mount->startblock + fs_info_sector, &data, &size);
- if (memcmp(data+0, "RRaA", 4) != 0 ||
- memcmp(data+0x1e4, "rrAa", 4) != 0)
+ mount->startblock + fs_info_sector, reply.buffer ,
+ &reply.buffer_size);
+ if (memcmp(reply.buffer+0, "RRaA", 4) != 0 ||
+ memcmp(reply.buffer+0x1e4, "rrAa", 4) != 0)
{
FAT_DEBUG_F("File System Information Sector signatures do not match,"
- " %"PRIx32", %"PRIx32, *(uint32_t*)(data+0),
- *(uint32_t*)(data+0x1e4));
+ " %"PRIx32", %"PRIx32, *(uint32_t*)(reply.buffer+0),
+ *(uint32_t*)(reply.buffer+0x1e4));
goto fs_check_failed;
}
- if (memcmp(data+0x1fe, "\x55\xAA", 2) != 0) {
+ if (memcmp(reply.buffer+0x1fe, "\x55\xAA", 2) != 0) {
FAT_DEBUG("File System Information Sector check bytes do not match");
goto fs_check_failed;
}
#ifdef FAT_DEBUG_ENABLED
FAT_DEBUG("dumping FSIS");
- printf("nr of free clusters: %"PRIu32"\n", *(uint32_t*)(data+0x1e8));
+ printf("nr of free clusters: %"PRIu32"\n", *(uint32_t*)(reply.buffer+0x1e8));
printf("most recently allocated cluster: %"PRIu32"\n",
- *(uint32_t*)(data+0x1ec));
+ *(uint32_t*)(reply.buffer+0x1ec));
printf("----------------\n");
#endif
- free(data);
data = NULL;
}
assert(!h->isdir);
- uint8_t *mybuf = NULL;
-
restart:
err = cl->rpc.vtbl.read(&cl->rpc, h->fh, h->pos, bytes,
- &msgerr, &mybuf, bytes_read);
+ &msgerr, buffer, bytes_read);
if (err_is_fail(err)) {
DEBUG_ERR(err, "transport error in read");
return err;
} else if (err_is_fail(msgerr)) {
- assert(mybuf == NULL);
if (err_no(msgerr) == FS_ERR_INVALID_FH && !restarts++) {
// revalidate handle and try again
msgerr = resolve_path(cl, h->path, &h->fh, NULL, NULL);
}
h->pos += *bytes_read;
- memcpy(buffer, mybuf, *bytes_read);
- free(mybuf);
if (*bytes_read < bytes) { // XXX: this can only mean EOF for ramfs
return VFS_ERR_EOF;
{
struct ramfs_handle *h = inhandle;
struct ramfs_client *cl = st;
- char *name;
- trivfs_fsize_t size;
- bool isdir;
- errval_t err, msgerr;
+
+ errval_t err;
int restarts = 0;
assert(h->isdir);
+ struct trivfs_readdir_response__rx_args reply;
restart:
err = cl->rpc.vtbl.readdir(&cl->rpc, h->fh, h->pos,
- &msgerr, &name, &isdir, &size);
+ &reply.err, reply.name, &reply.isdir, &reply.size);
if (err_is_fail(err)) {
DEBUG_ERR(err, "transport error in readdir");
return err;
- } else if (err_is_fail(msgerr)) {
- assert(name == NULL);
- if (err_no(msgerr) == FS_ERR_INVALID_FH && !restarts++) {
+ } else if (err_is_fail(reply.err)) {
+ if (err_no(reply.err) == FS_ERR_INVALID_FH && !restarts++) {
// revalidate handle and try again
if (h->fh == cl->rootfh) { // XXX: revalidate root
err = cl->rpc.vtbl.getroot(&cl->rpc, &cl->rootfh);
h->fh = cl->rootfh;
goto restart;
} else {
- msgerr = resolve_path(cl, h->path, &h->fh, NULL, NULL);
- if (err_is_ok(msgerr)) {
+ reply.err = resolve_path(cl, h->path, &h->fh, NULL, NULL);
+ if (err_is_ok(reply.err)) {
goto restart;
}
}
}
- if (err_no(msgerr) != FS_ERR_INDEX_BOUNDS) {
- DEBUG_ERR(msgerr, "server error in readdir");
+ if (err_no(reply.err) != FS_ERR_INDEX_BOUNDS) {
+ DEBUG_ERR(reply.err, "server error in readdir");
}
- return msgerr;
+ return reply.err;
}
h->pos++;
if (retname != NULL) {
- *retname = name;
+ *retname = strdup(reply.name);
}
if (info != NULL) {
- info->type = isdir ? VFS_DIRECTORY : VFS_FILE;
- info->size = size;
+ info->type = reply.isdir ? VFS_DIRECTORY : VFS_FILE;
+ info->size = reply.size;
}
return SYS_ERR_OK;
return LIB_ERR_NAMESERVICE_NOT_BOUND;
}
- char* record = NULL;
- octopus_trigger_id_t tid;
- errval_t error_code;
- err = r->vtbl.get(r, iface, NOP_TRIGGER, &record, &tid, &error_code);
+ struct octopus_get_response__rx_args reply;
+ err = r->vtbl.get(r, iface, NOP_TRIGGER, reply.output, &reply.tid, &reply.error_code);
if (err_is_fail(err)) {
goto out;
}
- err = error_code;
+ err = reply.error_code;
if (err_is_fail(err)) {
if (err_no(err) == OCT_ERR_NO_RECORD) {
err = err_push(err, XEON_PHI_ERR_CLIENT_DOMAIN_VOID);
}
xphi_dom_id_t domid = 0;
- err = oct_read(record, "_ { domid: %d }", &domid);
+ err = oct_read(reply.output, "_ { domid: %d }", &domid);
if (err_is_fail(err) || domid == 0) {
err = err_push(err, XEON_PHI_ERR_CLIENT_DOMAIN_VOID);
goto out;
*retdomid = domid;
}
- out: free(record);
-
+ out:
return err;
#endif
}
return LIB_ERR_NAMESERVICE_NOT_BOUND;
}
- char* record = NULL;
- errval_t error_code;
- err = r->vtbl.wait_for(r, iface, &record, &error_code);
+ struct octopus_wait_for_response__rx_args reply;
+ err = r->vtbl.wait_for(r, iface, reply.record, &reply.error_code);
if (err_is_fail(err)) {
goto out;
}
- err = error_code;
+ err = reply.error_code;
if (err_is_fail(err)) {
if (err_no(err) == OCT_ERR_NO_RECORD) {
err = err_push(err, XEON_PHI_ERR_CLIENT_DOMAIN_VOID);
}
xphi_dom_id_t domid = 0;
- err = oct_read(record, "_ { domid: %d }", &domid);
+ err = oct_read(reply.record, "_ { domid: %d }", &domid);
if (err_is_fail(err)) {
err = err_push(err, XEON_PHI_ERR_CLIENT_DOMAIN_VOID);
goto out;
}
out:
- free(record);
return err;
#endif
}
}
snprintf(record, len+1, format, iface, domid);
- char* ret = NULL;
octopus_trigger_id_t tid;
errval_t error_code;
- err = r->vtbl.set(r, record, 0, NOP_TRIGGER, 0, &ret, &tid, &error_code);
+ err = r->vtbl.set(r, record, 0, NOP_TRIGGER, 0, NULL, &tid, &error_code);
if (err_is_fail(err)) {
goto out;
}
where rpc_arg_var (RPCArgIn _ v) = v
rpc_arg_var (RPCArgOut _ v) = v
rpc_arg_var_name (Name n) = n
- rpc_arg_var_name (DynamicArray n _) = n
+ rpc_arg_var_name (DynamicArray n _ _) = n
get_meta_arg :: String -> String -> [(String, [(String, MetaArgument)])] -> Maybe MetaArgument
get_meta_arg nspc n metaargs = (lookup nspc metaargs) >>= (lookup n)
meta_arg_dma_size
]
dma_dyn_arg_size = case rpc_arg rpcargs $ rpc_dma_arg_name rpc of
- Just (RPCArgIn (Builtin UInt8) (DynamicArray _ l)) -> Just $ C.Variable l
+ Just (RPCArgIn (Builtin UInt8) (DynamicArray _ l _)) -> Just $ C.Variable l
_ -> Nothing
dma_arg_type_size = case lookup_typeref types $ rpc_arg_type $ fromJust $ rpc_arg rpcargs $ rpc_dma_arg_name rpc of
TArray (Builtin UInt8) _ length -> Just $ C.NumConstant length
pr_region_var = C.Variable "completed_st" `C.DerefField` "dma_region"
output_arg_expr :: Maybe Direction -> MessageArgument -> [C.Expr]
output_arg_expr _ (Arg (Builtin ErrVal) (Name "status")) = [C.Variable "SYS_ERR_OK"]
- output_arg_expr (Just RX) (Arg (Builtin UInt8) (DynamicArray _ _)) = [C.Variable dma_data_name, dma_size]
+ output_arg_expr (Just RX) (Arg (Builtin UInt8) (DynamicArray _ _ _)) = [C.Variable dma_data_name, dma_size]
output_arg_expr _ arg = error ("unrecoginized output argument " ++ (show arg))
dma_args = rpc_dma_args types msg
> nameOf :: Variable -> String
> nameOf (Name s) = s
-> nameOf (DynamicArray s _) = s
+> nameOf (DynamicArray s _ _) = s
Conversely, when marshaling or unmarshaling dynamic arrays, we need to
> listOfArgs :: String -> Variable -> String
> listOfArgs dereference (Name s) = dereference ++ s
-> listOfArgs dereference (DynamicArray name length) = dereference ++ name ++ ", " ++ length
+> listOfArgs dereference (DynamicArray name length _) = dereference ++ name ++ ", " ++ length
> callNameOf :: MessageDef -> String
-{-
+{-
BackendCommon: Common code used by most backends
Part of Flounder: a message passing IDL for Barrelfish
-- Variable used to refer to a continuation
intf_frameinfo_var = "_frameinfo"
+-- name of the maximum message size define
+msg_arg_size_name :: String -> String
+msg_arg_size_name ifname = ifscope ifname "_MAX_MESSAGE_SIZE"
+arg_size_name :: String -> String -> String -> String
+arg_size_name ifname fname argn= ifscope ifname ("_" ++ fname ++ "_" ++ argn ++ "_MAX_ARGUMENT_SIZE")
-- Name of the bind continuation function type for an interface type
intf_bind_cont_type :: String -> String
msg_sig_type ifn m TX = idscope ifn (msg_name m) "tx_method_fn"
msg_sig_type ifn m RX = idscope ifn (msg_name m) "rx_method_fn"
+msg_sig_type_rpc_rx :: String -> MessageDef -> String
+msg_sig_type_rpc_rx ifn m@(RPC _ _ _) = idscope ifn (msg_name m) "rpc_rx_method_fn"
+
-- Name of a given message definition
msg_name :: MessageDef -> String
msg_name (Message _ n _ _) = n
rpc_resp_name n = n ++ "_response"
-- Name of the struct holding message args for SAR
-msg_argstruct_name :: String -> String -> String
-msg_argstruct_name ifn n = idscope ifn n "args"
+msg_argstruct_name :: Direction -> String -> String -> String
+msg_argstruct_name TX ifn n = idscope ifn n "tx_args"
+msg_argstruct_name RX ifn n = idscope ifn n "rx_args"
-- Name of the union type holding all the arguments for a message
-binding_arg_union_type :: String -> String
-binding_arg_union_type ifn = ifscope ifn "arg_union"
+binding_arg_union_type :: Direction -> String -> String
+binding_arg_union_type TX ifn = ifscope ifn "tx_arg_union"
+binding_arg_union_type RX ifn = ifscope ifn "rx_arg_union"
-- Name of the C type for a concrete flounder type, struct, or enum
type_c_struct, type_c_enum :: String -> String -> String
type_c_type_dir RX ifn tr = type_c_type ifn tr
-- Array types in the msg args struct should only be pointers to the storage
-type_c_type_msgstruct :: String -> [TypeDef] -> TypeRef -> C.TypeSpec
-type_c_type_msgstruct ifn typedefs t
+type_c_type_msgstruct :: Direction -> String -> [TypeDef] -> TypeRef -> C.TypeSpec
+type_c_type_msgstruct TX ifn typedefs t
= case lookup_typeref typedefs t of
TArray tr n _ -> C.Ptr $ type_c_type ifn t
_ -> type_c_type ifn t
+type_c_type_msgstruct RX ifn typedefs t
+ = case lookup_typeref typedefs t of
+ _ -> type_c_type ifn t
-- Name of the struct type for the method vtable
intf_vtbl_type :: String -> Direction -> String
change_waitset_fn_type ifn = ifscope ifn "change_waitset_fn"
control_fn_type ifn = ifscope ifn "control_fn"
error_handler_fn_type ifn = ifscope ifn "error_handler_fn"
+receive_next_fn_type ifn = ifscope ifn "receive_next_fn"
+get_receiving_chanstate_fn_type ifn = ifscope ifn "get_receiving_chanstate_fn"
+
+-- Name of the type of a message handler
+msg_handler_fn_name :: String -> MessageDef -> String
+msg_handler_fn_name ifn m = idscope ifn (msg_name m) "handler_fn"
+
------------------------------------------------------------------------
msg_argdecl :: Direction -> String -> MessageArgument -> [C.Param]
msg_argdecl dir ifn (Arg tr (Name n)) =
[ C.Param (type_c_type_dir dir ifn tr) n ]
-msg_argdecl RX ifn (Arg tr (DynamicArray n l)) =
+msg_argdecl dir ifn (Arg tr (StringArray n l)) =
+ [ C.Param (type_c_type_dir dir ifn tr) n ]
+msg_argdecl RX ifn (Arg tr (DynamicArray n l _)) =
[ C.Param (C.Ptr $ type_c_type_dir RX ifn tr) n,
C.Param (type_c_type_dir RX ifn size) l ]
-msg_argdecl TX ifn (Arg tr (DynamicArray n l)) =
+msg_argdecl TX ifn (Arg tr (DynamicArray n l _)) =
[ C.Param (C.Ptr $ C.ConstT $ type_c_type_dir TX ifn tr) n,
C.Param (type_c_type_dir TX ifn size) l ]
-msg_argstructdecl :: String -> [TypeDef] -> MessageArgument -> [C.Param]
-msg_argstructdecl ifn typedefs (Arg tr (Name n)) =
- [ C.Param (type_c_type_msgstruct ifn typedefs tr) n ]
-msg_argstructdecl ifn typedefs a = msg_argdecl RX ifn a
-rpc_argdecl :: String -> RPCArgument -> [C.Param]
-rpc_argdecl ifn (RPCArgIn tr v) = msg_argdecl TX ifn (Arg tr v)
-rpc_argdecl ifn (RPCArgOut tr (Name n)) = [ C.Param (C.Ptr $ type_c_type ifn tr) n ]
-rpc_argdecl ifn (RPCArgOut tr (DynamicArray n l)) =
- [ C.Param (C.Ptr $ C.Ptr $ type_c_type ifn tr) n,
+msg_argstructdecl :: Direction -> String -> [TypeDef] -> MessageArgument -> [C.Param]
+msg_argstructdecl dir ifn typedefs (Arg tr (Name n)) =
+ [ C.Param (type_c_type_msgstruct dir ifn typedefs tr) n ]
+msg_argstructdecl RX ifn typedefs (Arg tr (StringArray n maxlen)) =
+ [ C.Param (C.Array maxlen $ C.TypeName "char") (n)]
+msg_argstructdecl TX ifn typedefs (Arg tr (StringArray n maxlen)) =
+ [ C.Param (type_c_type_dir TX ifn tr) n ]
+msg_argstructdecl RX ifn typedefs (Arg tr (DynamicArray n l maxlen)) =
+ [ C.Param (C.Array maxlen $ type_c_type ifn tr) (n),
+ C.Param (type_c_type ifn size) l ]
+msg_argstructdecl TX ifn typedefs (Arg tr (DynamicArray n l maxlen)) =
+ [ C.Param (C.Ptr $ C.ConstT $ type_c_type_dir TX ifn tr) n,
+ C.Param (type_c_type ifn size) l ]
+
+
+rpc_argdecl :: Direction -> String -> RPCArgument -> [C.Param]
+rpc_argdecl dir ifn (RPCArgIn tr v) = msg_argdecl dir ifn (Arg tr v)
+rpc_argdecl dir ifn (RPCArgOut tr (Name n)) = [ C.Param (C.Ptr $ type_c_type ifn tr) n ]
+rpc_argdecl dir ifn (RPCArgOut tr (StringArray n _)) = [ C.Param (type_c_type ifn tr) n ]
+rpc_argdecl dir ifn (RPCArgOut tr (DynamicArray n l _)) =
+ [ C.Param (C.Ptr $ type_c_type ifn tr) n,
C.Param (C.Ptr $ type_c_type ifn size) l ]
-- XXX: kludge wrapper to pass array types by reference in RPC
-rpc_argdecl2 :: String -> [TypeDef] -> RPCArgument -> [C.Param]
-rpc_argdecl2 ifn typedefs arg@(RPCArgOut tr (Name n))
+rpc_argdecl2 :: Direction -> String -> [TypeDef] -> RPCArgument -> [C.Param]
+rpc_argdecl2 dir ifn typedefs arg@(RPCArgOut tr (Name n))
= case lookup_typeref typedefs tr of
- TArray _ _ _ -> [ C.Param (C.Ptr $ C.Ptr $ type_c_type ifn tr) n ]
- _ -> rpc_argdecl ifn arg
-rpc_argdecl2 ifn _ arg = rpc_argdecl ifn arg
+ TArray _ _ _ -> [ C.Param (type_c_type ifn tr) n ]
+ _ -> rpc_argdecl dir ifn arg
+rpc_argdecl2 dir ifn _ arg = rpc_argdecl dir ifn arg
-- binding parameter for a function
binding_param ifname = C.Param (C.Ptr $ C.Struct $ intf_bind_type ifname) intf_bind_var
+binding_param2 ifname = C.Param (C.Ptr $ C.Struct $ intf_bind_type ifname) (intf_bind_var ++ "_")
--
binding_struct_init drv ifn binding_var waitset_ex tx_vtbl_ex = [
C.Ex $ C.Assignment (C.FieldOf binding_var "st") (C.Variable "NULL"),
C.Ex $ C.Assignment (C.FieldOf binding_var "waitset") waitset_ex,
+ C.Ex $ C.Assignment (C.FieldOf binding_var "send_waitset") (C.Variable "NULL"),
C.Ex $ C.Call "event_mutex_init" [C.AddressOf $ C.FieldOf binding_var "mutex", waitset_ex],
+ C.Ex $ C.Call "thread_mutex_init" [C.AddressOf $ C.FieldOf binding_var "rxtx_mutex"],
+ C.Ex $ C.Call "thread_mutex_init" [C.AddressOf $ C.FieldOf binding_var "send_mutex"],
C.Ex $ C.Assignment (C.FieldOf binding_var "can_send")
(C.Variable $ can_send_fn_name drv ifn),
C.Ex $ C.Assignment (C.FieldOf binding_var "register_send")
C.Ex $ C.Call "memset" [C.AddressOf $ C.FieldOf binding_var "rx_vtbl",
C.NumConstant 0,
C.Call "sizeof" [C.FieldOf binding_var "rx_vtbl"]],
+ C.Ex $ C.Call "memset" [C.AddressOf $ C.FieldOf binding_var "message_rx_vtbl",
+ C.NumConstant 0,
+ C.Call "sizeof" [C.FieldOf binding_var "message_rx_vtbl"]],
+ C.Ex $ C.Call "memset" [C.AddressOf $ C.FieldOf binding_var "rpc_rx_vtbl",
+ C.NumConstant 0,
+ C.Call "sizeof" [C.FieldOf binding_var "rpc_rx_vtbl"]],
C.Ex $ C.Call "flounder_support_waitset_chanstate_init"
[C.AddressOf $ C.FieldOf binding_var "register_chanstate"],
C.Ex $ C.Call "flounder_support_waitset_chanstate_init"
[C.Ex $ C.Assignment (C.FieldOf binding_var f) (C.NumConstant 0)
| f <- ["tx_msgnum", "rx_msgnum", "tx_msg_fragment", "rx_msg_fragment",
"tx_str_pos", "rx_str_pos", "tx_str_len", "rx_str_len"]],
- C.Ex $ C.Assignment (C.FieldOf binding_var "bind_cont") (C.Variable "NULL")]
+ C.Ex $ C.Assignment (C.FieldOf binding_var "incoming_token") (C.NumConstant 0),
+ C.Ex $ C.Assignment (C.FieldOf binding_var "outgoing_token") (C.NumConstant 0)]
binding_struct_destroy :: String -> C.Expr -> [C.Stmt]
binding_struct_destroy ifn binding_var
C.If (C.Binary C.NotEquals (cont_ex `C.FieldOf` "handler") (C.Variable "NULL"))
[localvar (C.TypeName "errval_t") "_err" Nothing,
C.Ex $ C.Assignment errvar $ C.Call "flounder_support_register"
- [bindvar `C.DerefField` "waitset",
+ [C.Variable "send_waitset",
C.AddressOf $ bindvar `C.DerefField` "tx_cont_chanstate",
cont_ex,
C.Variable "false"],
C.If (C.Call "err_is_fail" [errvar])
[C.If (C.Binary C.Equals (C.Call "err_no" [errvar])
(C.Variable "LIB_ERR_CHAN_ALREADY_REGISTERED"))
- [C.Return $ C.Variable "FLOUNDER_ERR_TX_BUSY"]
- [C.Ex $ C.Call "assert" [C.Unary C.Not $ C.StringConstant "shouldn't happen"],
+ [C.Ex $ C.Call "thread_mutex_unlock" [C.AddressOf $ C.DerefField bindvar "send_mutex"],
+ C.Ex $ C.Call "assert" [C.Binary C.NotEquals (cont_ex `C.FieldOf` "handler") (C.Variable "blocking_cont")],
+ C.Return $ C.Variable "FLOUNDER_ERR_TX_BUSY"]
+ [C.Ex $ C.Call "thread_mutex_unlock" [C.AddressOf $ C.DerefField bindvar "send_mutex"],
+ C.Ex $ C.Call "assert" [C.Unary C.Not $ C.StringConstant "shouldn't happen"],
C.Return $ errvar] ] []
] []
] where
errvar = C.Variable "_err"
+block_sending :: C.Expr -> [C.Stmt]
+block_sending cont_ex = [
+ C.If (C.Binary C.Equals (cont_ex `C.FieldOf` "handler") (C.Variable "blocking_cont"))
+ [C.If (C.Binary C.Equals binding_error (C.Variable "SYS_ERR_OK")) [
+ C.Ex $ C.Assignment binding_error $ C.Call "wait_for_channel"
+ [C.Variable "send_waitset", tx_cont_chanstate, C.AddressOf binding_error]
+ ] [
+ C.Ex $ C.Call "flounder_support_deregister_chan" [tx_cont_chanstate]
+ ]
+ ] []
+ ] where
+ errvar = C.Variable "_err"
+ mask = C.CallInd (C.DerefField bindvar "get_receiving_chanstate") [bindvar]
+ tx_cont_chanstate = C.AddressOf $ bindvar `C.DerefField` "tx_cont_chanstate"
+
-- starting a send: just a debug hook
start_send :: String -> String -> String -> [MessageArgument] -> [C.Stmt]
start_send drvn ifn mn msgargs
_ -> False
-- finished recv: debug, run handler and clean up
-finished_recv :: String -> String -> [TypeDef] -> String -> [MessageArgument] -> [C.Stmt]
-finished_recv drvn ifn typedefs mn msgargs
- = [C.Ex $ C.Call "FL_DEBUG" [C.StringConstant $
+finished_recv :: String -> String -> [TypeDef] -> MessageType -> String -> [MessageArgument] -> [C.Stmt]
+finished_recv drvn ifn typedefs mtype mn msgargs
+ = [ C.Ex $ C.Call "FL_DEBUG" [C.StringConstant $
drvn ++ " RX " ++ ifn ++ "." ++ mn ++ "\n"],
- C.Ex $ C.Call "assert" [C.Binary C.NotEquals handler (C.Variable "NULL")],
- C.Ex $ C.CallInd handler (bindvar:args),
- C.Ex $ C.Assignment rx_msgnum_field (C.NumConstant 0)]
+ C.If (C.Binary C.NotEquals handler (C.Variable "NULL"))
+ [C.Ex $ C.Assignment (C.FieldOf message_chanstate "token") binding_incoming_token,
+ C.Ex $ C.CallInd handler (bindvar:args)]
+ [C.Ex $ C.Assignment (C.FieldOf message_chanstate "token") binding_incoming_token,
+ C.Ex $ C.Call "flounder_support_trigger_chan" [C.AddressOf message_chanstate],
+ C.Ex $ C.Assignment (C.Variable "no_register") (C.NumConstant 1)],
+ C.Ex $ C.Assignment rx_msgnum_field (C.NumConstant 0)]
where
rx_msgnum_field = C.DerefField bindvar "rx_msgnum"
handler = C.DerefField bindvar "rx_vtbl" `C.FieldOf` mn
mkargs tr (Name n) = case lookup_typeref typedefs tr of
TArray _ _ _ -> [C.DerefPtr $ rx_union_elem mn n]
_ -> [rx_union_elem mn n]
- mkargs _ (DynamicArray n l) = [rx_union_elem mn n, rx_union_elem mn l]
+ mkargs _ (StringArray n l) = [rx_union_elem mn n]
+ mkargs _ (DynamicArray n l _) = [rx_union_elem mn n, rx_union_elem mn l]
+ binding_incoming_token = C.DerefField bindvar "incoming_token"
+ message_chanstate = C.SubscriptOf (C.DerefField bindvar "message_chanstate") (C.Variable $ msg_enum_elem_name ifn mn)
+
+finished_recv_nocall :: String -> String -> [TypeDef] -> MessageType -> String -> [MessageArgument] -> [C.Stmt]
+finished_recv_nocall drvn ifn typedefs mtype mn msgargs
+ = [ C.Ex $ C.Call "FL_DEBUG" [C.StringConstant $
+ drvn ++ " RX " ++ ifn ++ "." ++ mn ++ "\n"],
+ C.If (C.Binary C.NotEquals handler (C.Variable "NULL"))
+ [C.Ex $ C.Assignment (C.Variable "call_msgnum") (C.Variable $ msg_enum_elem_name ifn mn)]
+ [C.Ex $ C.Assignment (C.FieldOf message_chanstate "token") binding_incoming_token,
+ C.Ex $ C.Call "flounder_support_trigger_chan" [C.AddressOf message_chanstate],
+ C.Ex $ C.Assignment (C.Variable "no_register") (C.NumConstant 1)],
+ C.Ex $ C.Assignment rx_msgnum_field (C.NumConstant 0)]
+ where
+ rx_msgnum_field = C.DerefField bindvar "rx_msgnum"
+ handler = C.DerefField bindvar "rx_vtbl" `C.FieldOf` mn
+ binding_incoming_token = C.DerefField bindvar "incoming_token"
+ message_chanstate = C.SubscriptOf (C.DerefField bindvar "message_chanstate") (C.Variable $ msg_enum_elem_name ifn mn)
+
+-- call callback, directly from a receiving handler
+call_handler :: String -> String -> [TypeDef] -> MessageType -> String -> [MessageArgument] -> [C.Stmt]
+call_handler drvn ifn typedefs mtype mn msgargs
+ = [C.Ex $ C.CallInd handler (bindvar:args)]
+ where
+ handler = C.DerefField bindvar "rx_vtbl" `C.FieldOf` mn
+ args = concat [mkargs tr a | Arg tr a <- msgargs]
+ mkargs tr (Name n) = case lookup_typeref typedefs tr of
+ TArray _ _ _ -> [C.DerefPtr $ rx_union_elem mn n]
+ _ -> [rx_union_elem mn n]
+ mkargs _ (StringArray n l) = [rx_union_elem mn n]
+ mkargs _ (DynamicArray n l _) = [rx_union_elem mn n, rx_union_elem mn l]
+
+-- call callback, from a message handler
+call_message_handler_msgargs :: String -> String -> [TypeDef] -> [MessageArgument] -> [C.Stmt]
+call_message_handler_msgargs ifn mn typedefs msgargs
+ = [C.Ex $ C.CallInd handler (bindvar:args)]
+ where
+ handler = C.DerefField bindvar "message_rx_vtbl" `C.FieldOf` mn
+ args = concat [mkargs a | Arg tr a <- msgargs]
+ mkargs (Name n) = [local_rx_union_elem mn n]
+ mkargs (StringArray n l) = [local_rx_union_elem mn n]
+ mkargs (DynamicArray n l _) = [local_rx_union_elem mn n, local_rx_union_elem mn l]
+
+-- call callback, from a rpc handler
+call_message_handler_rpcargs :: String -> String -> [TypeDef] -> [RPCArgument] -> [C.Stmt]
+call_message_handler_rpcargs ifn mn typedefs msgargs
+ = [C.Ex $ C.Call "assert" [handler],
+ C.Ex $ C.CallInd handler (bindvar:args)]
+ where
+ handler = C.DerefField bindvar "message_rx_vtbl" `C.FieldOf` (rpc_call_name mn)
+ args = concat [mkargs a | RPCArgIn tr a <- msgargs]
+ mkargs (Name n) = [local_rx_union_elem mn n]
+ mkargs (StringArray n l) = [local_rx_union_elem mn n]
+ mkargs (DynamicArray n l _) = [local_rx_union_elem mn n, local_rx_union_elem mn l]
+
+-- call rpc callback
+call_rpc_handler :: String -> String -> [TypeDef] -> [RPCArgument] -> [C.Stmt]
+call_rpc_handler ifn mn typedefs msgargs
+ = [C.Ex $ C.CallInd handler (bindvar:args)]
+ where
+ handler = C.DerefField bindvar "rpc_rx_vtbl" `C.FieldOf` (rpc_call_name mn)
+ args = concat [mkargs a | a <- msgargs]
+ mkargs (RPCArgIn _ (Name n)) = [local_rx_union_elem mn n]
+ mkargs (RPCArgIn _ (StringArray n l)) = [local_rx_union_elem mn n]
+ mkargs (RPCArgIn _ (DynamicArray n l _)) = [local_rx_union_elem mn n, local_rx_union_elem mn l]
+ mkargs (RPCArgOut tr (Name n)) = case lookup_typeref typedefs tr of
+ TArray _ _ _ -> [C.DerefPtr $ local_tx_union_elem mn n]
+ _ -> [C.AddressOf $ local_tx_union_elem mn n]
+ mkargs (RPCArgOut _ (StringArray n l)) = [local_tx_union_elem mn n]
+ mkargs (RPCArgOut _ (DynamicArray n l _)) = [local_tx_union_elem mn n, C.AddressOf $ local_tx_union_elem mn l]
+
+-- send response
+send_response :: String -> String -> [TypeDef] -> [RPCArgument] -> [C.Stmt]
+send_response ifn mn typedefs msgargs
+ = [C.Ex $ C.Call "assert" [handler],
+ C.Ex $ C.Assignment errvar $ C.CallInd handler (bindvar:cont:args),
+ C.Ex $ C.Call "assert" [C.Call "err_is_ok" [errvar]]]
+ where
+ handler = C.DerefField bindvar "tx_vtbl" `C.FieldOf` (rpc_resp_name mn)
+ args = concat [mkargs tr a | RPCArgOut tr a <- msgargs]
+ mkargs tr (Name n) = case lookup_typeref typedefs tr of
+ TArray _ _ _ -> [C.DerefPtr $ local_tx_union_elem mn n]
+ _ -> [local_tx_union_elem mn n]
+ mkargs _ (StringArray n l) = [local_tx_union_elem mn n]
+ mkargs _ (DynamicArray n l _) = [local_tx_union_elem mn n, local_tx_union_elem mn l]
+ cont = C.Variable "BLOCKING_CONT"
tx_arg_assignment :: String -> [TypeDef] -> String -> MessageArgument -> C.Stmt
tx_arg_assignment ifn typedefs mn (Arg tr v) = case v of
Name an -> C.Ex $ C.Assignment (tx_union_elem mn an) (srcarg an)
- DynamicArray an len -> C.StmtList [
+ StringArray an _ -> C.Ex $ C.Assignment (tx_union_elem mn an) ((C.Variable an))
+ DynamicArray an len _ -> C.StmtList [
C.Ex $ C.Assignment (tx_union_elem mn an) (C.Cast (C.Ptr typespec) (C.Variable an)),
C.Ex $ C.Assignment (tx_union_elem mn len) (C.Variable len)]
where
_ -> C.Variable an
+-- extracts the size of the arguemnts of a message
+extract_msg_size :: MessageArgument -> Integer
+extract_msg_size (Arg tr (Name an)) = 0
+extract_msg_size (Arg tr (StringArray an maxlen)) = maxlen
+extract_msg_size (Arg tr (DynamicArray an len maxlen)) = maxlen
+
+-- extracts the size of the arguemnts of an RPC (in)
+extract_rpc_size_in :: RPCArgument -> Integer
+extract_rpc_size_in (RPCArgIn tr (Name an)) = 0
+extract_rpc_size_in (RPCArgIn tr (StringArray an maxlen)) = maxlen
+extract_rpc_size_in (RPCArgIn tr (DynamicArray an len maxlen)) = maxlen
+
+-- extracts the size of the arguemnts of an RPC (out)
+extract_rpc_size_out :: RPCArgument -> Integer
+extract_rpc_size_out (RPCArgOut tr (Name an)) = 0
+extract_rpc_size_out (RPCArgOut tr (StringArray an maxlen)) = maxlen
+extract_rpc_size_out (RPCArgOut tr (DynamicArray an len maxlen)) = maxlen
+
+-- extract the size of arguemnts
+msg_arg_extract_length :: MessageDef -> Integer
+msg_arg_extract_length (RPC n [] _) = 0
+msg_arg_extract_length (RPC n args _) = maximum [ sum $ [ extract_rpc_size_in arg | arg <- args], sum $ [ extract_rpc_size_out arg | arg <- args]]
+msg_arg_extract_length (Message mtype n [] _) = 0
+msg_arg_extract_length (Message mtype n args _) = sum $ [ extract_msg_size arg | arg <- args]
+
+
+
+-- checks the size of the MSG arguments
+tx_fn_arg_check_size :: String -> [TypeDef] -> String -> MessageArgument -> C.Stmt
+tx_fn_arg_check_size ifn typedefs mn (Arg tr v) = case v of
+ Name an -> C.SComment (an ++ " has a base type. no length check")
+ StringArray an maxlen -> C.StmtList [
+ C.SComment ("checking datalength of " ++ an),
+ C.If (C.Binary C.And (C.Variable an)
+ (C.Binary C.GreaterThanEq (C.Call "strlen" [C.Variable an]) (C.Binary C.Minus (C.NumConstant maxlen) (C.NumConstant 1)))) [
+ C.Return (C.Variable "FLOUNDER_ERR_TX_MSG_SIZE")
+ ] []
+ ]
+ DynamicArray an len maxlen -> C.StmtList [
+ C.SComment ("checking datalength of " ++ an),
+ C.If (C.Binary C.GreaterThanEq (C.Variable len) (C.NumConstant maxlen)) [
+ C.Return (C.Variable "FLOUNDER_ERR_TX_MSG_SIZE")
+ ] []
+ ]
+
+-- checks the size of the RPC arguments
+tx_fn_arg_check_size_rpc :: String -> [TypeDef] -> String -> RPCArgument -> C.Stmt
+tx_fn_arg_check_size_rpc ifn typedefs mn (RPCArgIn tr v) = case v of
+ Name an -> C.SComment (an ++ " has a base type. no length check")
+ StringArray an maxlen -> C.StmtList [
+ C.SComment ("checking datalength of " ++ an),
+ C.If (C.Binary C.GreaterThanEq (C.Call "strlen" [C.Variable an]) (C.Binary C.Minus (C.NumConstant maxlen) (C.NumConstant 1))) [
+ C.Return (C.Variable "FLOUNDER_ERR_TX_MSG_SIZE")
+ ] []
+ ]
+ DynamicArray an len maxlen -> C.StmtList [
+ C.SComment ("checking datalength of " ++ an),
+ C.If (C.Binary C.GreaterThanEq (C.Variable len) (C.NumConstant maxlen)) [
+ C.Return (C.Variable "FLOUNDER_ERR_TX_MSG_SIZE")
+ ] []
+ ]
+tx_fn_arg_check_size_rpc ifn typedefs mn (RPCArgOut tr v) = C.SComment (" Is out arg")
+
+
tx_union_elem :: String -> String -> C.Expr
tx_union_elem mn fn
= bindvar `C.DerefField` "tx_union" `C.FieldOf` mn `C.FieldOf` fn
rx_union_elem mn fn
= bindvar `C.DerefField` "rx_union" `C.FieldOf` mn `C.FieldOf` fn
+local_rx_union_elem :: String -> String -> C.Expr
+local_rx_union_elem mn fn
+ = (C.Variable "arguments") `C.FieldOf` fn
+
+local_tx_union_elem :: String -> String -> C.Expr
+local_tx_union_elem mn fn
+ = (C.Variable "result") `C.FieldOf` fn
+
-- misc common bits of C
localvar = C.VarDecl C.NoScope C.NonConst
errvar = C.Variable "err"
bindvar = C.Variable intf_bind_var
-report_user_err ex = C.Ex $ C.CallInd (C.DerefField bindvar "error_handler") [bindvar, ex]
+binding_error = C.DerefField bindvar "error"
+clear_error = C.Ex $ C.Assignment binding_error (C.Variable "SYS_ERR_OK")
+report_user_err ex = C.StmtList [
+ C.Ex $ C.Assignment (C.DerefField bindvar "error") ex,
+ C.If (C.DerefField bindvar "error_handler") [
+ C.Ex $ C.CallInd (C.DerefField bindvar "error_handler") [bindvar, ex]
+ ] []]
+
report_user_tx_err ex = C.StmtList [
report_user_err ex,
C.Ex $ C.Assignment tx_msgnum_field (C.NumConstant 0),
pp_expr (Assignment e1 e2) = (pp_expr e1) ++ " = " ++ (pp_par_expr e2)
pp_expr (Unary o e) = (pp_unop o) ++ (pp_par_expr e)
pp_expr (Binary o e1 e2)
- = (pp_par_expr e1) ++" " ++ (pp_binop o) ++ " "++(pp_par_expr e2)
+ = "(" ++ (pp_par_expr e1) ++" " ++ (pp_binop o) ++ " "++(pp_par_expr e2) ++ ")"
pp_expr (Ternary e1 e2 e3)
= (pp_par_expr e1) ++ " ? " ++ (pp_par_expr e2) ++ " : " ++ (pp_par_expr e3)
pp_expr (FieldOf e s) = (pp_par_expr e) ++ "." ++ s
-{-
+{-
GCBackend: Flounder stub generator for generic code
Part of Flounder: a message passing IDL for Barrelfish
import Data.Char
import qualified CAbsSyntax as C
-import Syntax (Interface (Interface))
-import GHBackend (flounder_backends, export_fn_name, bind_fn_name, accept_fn_name, connect_fn_name)
+import Syntax (Interface (Interface), MessageDef(Message, RPC), TypeDef, MessageType(MMessage, MCall, MResponse), RPCArgument(RPCArgIn, RPCArgOut))
+import GHBackend (flounder_backends, export_fn_name, bind_fn_name, accept_fn_name, connect_fn_name, connect_handlers_fn_name, disconnect_handlers_fn_name)
+import qualified Backend
import BackendCommon
import LMP (lmp_bind_type, lmp_bind_fn_name)
import qualified UMP (bind_type, bind_fn_name)
unlines $ C.pp_unit $ stub_body infile interface
stub_body :: String -> Interface -> C.Unit
-stub_body infile (Interface ifn descr _) = C.UnitList [
+stub_body infile (Interface ifn descr decls) = C.UnitList [
intf_preamble infile ifn descr,
C.Blank,
connect_fn_def ifn]
+compile_message_handlers :: String -> String -> Interface -> String
+compile_message_handlers infile outfile interface =
+ unlines $ C.pp_unit $ stub_body_message_handlers infile interface
+
+stub_body_message_handlers :: String -> Interface -> C.Unit
+stub_body_message_handlers infile (Interface ifn descr decls) = C.UnitList [
+ intf_preamble infile ifn descr,
+ C.Blank,
+
+ C.Include C.Standard "barrelfish/barrelfish.h",
+ C.Include C.Standard "flounder/flounder_support.h",
+ C.Include C.Standard ("if/" ++ ifn ++ "_defs.h"),
+ C.Blank,
+
+ C.MultiComment [ "Message handlers" ],
+ C.UnitList [ msg_handler ifn m types | m@(Message MMessage _ _ _) <- messages ],
+ C.UnitList [ msg_handler ifn m types | m@(Message MResponse _ _ _) <- messages ],
+ C.UnitList [ msg_handler ifn m types | m <- rpcs ],
+ C.Blank,
+
+ C.MultiComment [ "Connect handlers function" ],
+ connect_handlers_fn_def ifn messages,
+ C.Blank,
+
+ C.MultiComment [ "Disconnect handlers function" ],
+ disconnect_handlers_fn_def ifn messages,
+ C.Blank]
+
+ where
+ (types, messagedecls) = Backend.partitionTypesMessages decls
+ messages = rpcs_to_msgs messagedecls
+ rpcs = [m | m@(RPC _ _ _) <- messagedecls]
+
+
+msg_handler :: String -> MessageDef -> [TypeDef] -> C.Unit
+msg_handler ifname msg@(Message _ mn args _) types = C.FunctionDef C.Static (C.TypeName "void") name [C.Param (C.Ptr C.Void) "arg"] [
+ localvar (C.Ptr $ C.Struct $ intf_bind_type ifname)
+ intf_bind_var (Just $ C.Variable "arg"),
+ localvar (C.TypeName "errval_t") "err" Nothing,
+ if null args then C.SBlank else localvar (C.Struct $ msg_argstruct_name RX ifname mn) "arguments" (Just (bindvar `C.DerefField` "rx_union" `C.FieldOf` mn)),
+ C.SBlank,
+
+ C.Ex $ C.Assignment errvar $ C.CallInd receive_next [bindvar],
+ C.Ex $ C.Call "assert" [C.Call "err_is_ok" [errvar]],
+ C.StmtList $ call_message_handler_msgargs ifname mn types args
+ ]
+ where
+ name = msg_handler_fn_name ifname msg
+ receive_next = C.DerefField bindvar "receive_next"
+
+msg_handler ifname msg@(RPC mn args a) types = C.FunctionDef C.Static (C.TypeName "void") name [C.Param (C.Ptr C.Void) "arg"] [
+ localvar (C.Ptr $ C.Struct $ intf_bind_type ifname)
+ intf_bind_var (Just $ C.Variable "arg"),
+ localvar (C.TypeName "errval_t") "err" Nothing,
+ if null in_args then C.SBlank else localvar (C.Struct $ msg_argstruct_name RX ifname (rpc_call_name mn)) "arguments" (Just (bindvar `C.DerefField` "rx_union" `C.FieldOf` (rpc_call_name mn))),
+ localvar (C.TypeName "uint32_t") "token" (Just $ binding_incoming_token),
+ C.SBlank,
+
+ C.Ex $ C.Assignment errvar $ C.CallInd receive_next [bindvar],
+ C.Ex $ C.Call "assert" [C.Call "err_is_ok" [errvar]],
+ C.If (rpc_rx_handler) [
+ if null out_args then C.SBlank else localvar (C.Struct $ msg_argstruct_name RX ifname (rpc_resp_name mn)) "result" Nothing,
+ C.StmtList $ call_rpc_handler ifname mn types args,
+ C.Ex $ C.Call "thread_set_outgoing_token" [C.Binary C.BitwiseAnd (C.Variable "token") (C.Variable "~1" )],
+ C.StmtList $ send_response ifname mn types args
+ ] [
+ C.StmtList $ call_message_handler_rpcargs ifname mn types args
+ ]
+ ]
+ where
+ name = msg_handler_fn_name ifname (RPC (rpc_call_name mn) args a)
+ receive_next = C.DerefField bindvar "receive_next"
+ rpc_rx_handler = C.DerefField bindvar "rpc_rx_vtbl" `C.FieldOf` (rpc_call_name mn)
+ in_args = [a | RPCArgIn tr a <- args]
+ out_args = [a | RPCArgOut tr a <- args]
+ tx_handler = C.DerefField bindvar "tx_vtbl" `C.FieldOf` (rpc_resp_name mn)
+ binding_outgoing_token = C.DerefField bindvar "outgoing_token"
+ binding_incoming_token = C.DerefField bindvar "incoming_token"
+
+connect_handlers_fn_def :: String -> [MessageDef] -> C.Unit
+connect_handlers_fn_def n messages =
+ C.FunctionDef C.Static (C.TypeName "errval_t") (connect_handlers_fn_name n)
+ [C.Param (C.Ptr $ C.Struct $ intf_bind_type n) intf_bind_var] [
+ localvar (C.TypeName "errval_t") "err" Nothing,
+
+ C.StmtList [connect_handler n m | m <- messages],
+ C.Return $ C.Variable "SYS_ERR_OK"
+ ]
+
+connect_handler :: String -> MessageDef -> C.Stmt
+connect_handler n msg@(Message _ mn _ _) = C.StmtList [
+ C.Ex $ C.Call "flounder_support_waitset_chanstate_init_persistent" [message_chanstate],
+ C.Ex $ C.Assignment errvar $ C.Call "flounder_support_register" [waitset, message_chanstate, closure, C.Variable "false"],
+ C.Ex $ C.Call "assert" [C.Call "err_is_ok" [errvar]]
+ ]
+ where
+ waitset = bindvar `C.DerefField` "waitset"
+ message_chanstate = C.Binary C.Plus (C.DerefField bindvar "message_chanstate") (C.Variable $ msg_enum_elem_name n mn)
+ closure = C.StructConstant "event_closure"
+ [("handler", C.Variable $ msg_handler_fn_name n msg), ("arg", bindvar)]
+
+disconnect_handlers_fn_def :: String -> [MessageDef] -> C.Unit
+disconnect_handlers_fn_def n messages =
+ C.FunctionDef C.Static (C.TypeName "errval_t") (disconnect_handlers_fn_name n)
+ [C.Param (C.Ptr $ C.Struct $ intf_bind_type n) intf_bind_var] [
+ C.StmtList [disconnect_handler n m | m <- messages],
+ C.Return $ C.Variable "SYS_ERR_OK"
+ ]
+
+disconnect_handler :: String -> MessageDef -> C.Stmt
+disconnect_handler n msg@(Message _ mn _ _) = C.StmtList [
+ C.Ex $ C.Call "flounder_support_deregister_chan" [message_chanstate]
+ ]
+ where
+ message_chanstate = C.Binary C.Plus (C.DerefField bindvar "message_chanstate") (C.Variable $ msg_enum_elem_name n mn)
+
export_fn_def :: String -> C.Unit
export_fn_def n =
C.FunctionDef C.NoScope (C.TypeName "errval_t") (export_fn_name n) params [
[C.Ex $ C.Call "assert" [C.Unary C.Not $ C.StringConstant "invalid state"]],
C.SBlank,
C.Label "out",
+ C.Ex $ C.Call (connect_handlers_fn_name ifn) [C.Variable intf_bind_var],
C.Ex $ C.CallInd (C.Cast (C.Ptr $ C.TypeName $ intf_bind_cont_type ifn)
(bindst `C.DerefField` "callback"))
[bindst `C.DerefField` "st", errvar, C.Variable intf_bind_var],
-{-
+{-
GHBackend: Flounder stub generator for generic header files
Part of Flounder: a message passing IDL for Barrelfish
export_fn_name n = ifscope n "export"
bind_fn_name n = ifscope n "bind"
+connect_handlers_fn_name n = ifscope n "connect_handlers"
+disconnect_handlers_fn_name n = ifscope n "disconnect_handlers"
+
+rpc_rx_vtbl_type ifn = ifscope ifn "rpc_rx_vtbl"
+
------------------------------------------------------------------------
-- Language mapping: Create the generic header file for the interface
------------------------------------------------------------------------
let
(types, messagedecls) = Backend.partitionTypesMessages decls
messages = rpcs_to_msgs messagedecls
+ rpcs = [m | m@(RPC _ _ _) <- messagedecls]
in
[ intf_preamble infile name descr,
C.Blank,
C.Include C.Standard "flounder/flounder.h",
+ C.Include C.Standard "flounder/flounder_support.h",
C.Blank,
C.MultiComment [ "Concrete type definitions" ],
change_waitset_fn_typedef name,
control_fn_typedef name,
error_handler_fn_typedef name,
+ receive_next_fn_typedef name,
+ get_receiving_chanstate_fn_typedef name,
C.Blank,
C.MultiComment [ "Enumeration for message numbers" ],
C.UnitList [ msg_signature RX name m | m <- messages ],
C.Blank,
- C.MultiComment [ "Struct type for holding the args for each msg" ],
- C.UnitList [ msg_argstruct name types m | m <- messages ],
+ C.MultiComment [ "RPC RX function signatures" ],
+ C.UnitList [ msg_signature_rpc_rx name types (binding_param name) m
+ | m <- rpcs ],
+ C.Blank,
+
+ C.MultiComment [ "Struct type for holding the RX args for each msg" ],
+ C.UnitList [ msg_argstruct RX name types m | m <- messages ],
+ C.Blank,
+
+ C.MultiComment [ "Struct type for holding the TX args for each msg" ],
+ C.UnitList [ msg_argstruct TX name types m | m <- messages ],
+ C.Blank,
+
+ C.MultiComment [ "Union type for all message arguments" ],
+ intf_union RX name messages,
C.Blank,
C.MultiComment [ "Union type for all message arguments" ],
- intf_union name messages,
+ intf_union TX name messages,
+ C.Blank,
+
+ C.MultiComment [ "Maximum Transfer Size" ],
+ msg_arg_sizes name types messages,
+ msg_arg_size name types messages,
C.Blank,
C.MultiComment [ "VTable struct definition for the interface (transmit)" ],
intf_vtbl name RX messages,
C.Blank,
+ C.MultiComment [ "VTable struct definition for the rpc interface (receive)" ],
+ rpc_rx_vtbl_decl name rpcs,
+ C.Blank,
+
C.MultiComment [ "Incoming connect callback type" ],
connect_callback_fn name,
C.Blank,
params = [ firstparam ] ++ opt_continuation ++ concat payload
payload = case m of
Message _ _ args _ -> [ msg_argdecl dirn ifname a | a <- args ]
- RPC s args _ -> [ rpc_argdecl2 ifname typedefs a | a <- args ]
+ RPC s args _ -> [ rpc_argdecl2 TX ifname typedefs a | a <- args ]
msg_signature :: Direction -> String -> MessageDef -> C.Unit
msg_signature dir ifn = msg_signature_generic dir ifn [] (binding_param ifn)
+msg_signature_rpc_rx :: String -> [TypeDef] -> C.Param -> MessageDef -> C.Unit
+msg_signature_rpc_rx ifname typedefs firstparam m@(RPC s args _) = C.TypeDef (C.Function C.NoScope (C.TypeName "errval_t") params) name
+ where
+ name = msg_sig_type_rpc_rx ifname m
+ params = [ firstparam ] ++ concat payload
+ payload = [rpc_argdecl2 RX ifname typedefs a | a <- args]
+
+rpc_rx_vtbl_decl :: String -> [MessageDef] -> C.Unit
+rpc_rx_vtbl_decl n ml =
+ C.StructDecl (rpc_rx_vtbl_type n) [ param n m | m <- ml ]
+ where
+ param ifn m = C.Param (C.Ptr $ C.TypeName $ msg_sig_type_rpc_rx ifn m) ((msg_name m) ++ "_call")
--
--- Generate a struct to hold the arguments of a message while it's being sent.
+-- Get the maximum size of the arguments
--
-msg_argstruct :: String -> [TypeDef] -> MessageDef -> C.Unit
-msg_argstruct ifname typedefs m@(RPC n args _) =
- C.StructDecl (msg_argstruct_name ifname n)
- (concat [ rpc_argdecl ifname a | a <- args ])
-msg_argstruct ifname typedefs m@(Message _ n [] _) = C.NoOp
-msg_argstruct ifname typedefs m@(Message _ n args _) =
- let tn = msg_argstruct_name ifname n
- in
- C.StructDecl tn (concat [ msg_argstructdecl ifname typedefs a
- | a <- args ])
+msg_arg_size :: String -> [TypeDef] -> [MessageDef] -> C.Unit
+msg_arg_size ifname typedefs messages = C.Define (msg_arg_size_name ifname) []
+ (C.pp_expr (C.SizeOfT $ C.Union $ binding_arg_union_type RX ifname))
+
+msg_arg_sizes :: String -> [TypeDef] -> [MessageDef] -> C.Unit
+msg_arg_sizes ifname typedefs messages =
+ C.UnitList [ C.UnitList $ define_msg_arg_size ifname m | m <- messages ]
+
+-- extracts the size of the arguemnts of a message
+define_msg_size :: String -> String-> MessageArgument -> C.Unit
+define_msg_size ifn fn (Arg tr (Name an)) = C.NoOp
+define_msg_size ifn fn (Arg tr (StringArray an maxlen)) = C.Define (arg_size_name ifn fn an) [] (show maxlen)
+define_msg_size ifn fn (Arg tr (DynamicArray an len maxlen)) = C.Define (arg_size_name ifn fn an) [] (show maxlen)
+
+
+-- extracts the size of the arguemnts of an RPC (out)
+define_rpc_size :: String -> String-> RPCArgument -> C.Unit
+define_rpc_size ifn fn (RPCArgOut tr (Name an)) = C.NoOp
+define_rpc_size ifn fn (RPCArgIn _ _) = C.NoOp
+define_rpc_size ifn fn (RPCArgOut tr (StringArray an maxlen)) = C.Define (arg_size_name ifn fn an) [] (show maxlen)
+define_rpc_size ifn fn (RPCArgOut tr (DynamicArray an len maxlen)) = C.Define (arg_size_name ifn fn an) [] (show maxlen)
+
+-- extract the size of arguemnts
+define_msg_arg_size :: String-> MessageDef -> [C.Unit]
+define_msg_arg_size ifn (RPC n [] _) = []
+define_msg_arg_size ifn (RPC n args _) = [define_rpc_size ifn n arg | arg <- args]
+define_msg_arg_size ifn (Message mtype n [] _) = []
+define_msg_arg_size ifn (Message mtype n args _) = [define_msg_size ifn n arg | arg <- args]
+
+
+
+--
+-- Generate a struct to hold the arguments of a message while it's being sent.
+--
+msg_argstruct :: Direction -> String -> [TypeDef] -> MessageDef -> C.Unit
+msg_argstruct dir ifname typedefs m@(RPC n args _) =
+ C.StructDecl (msg_argstruct_name dir ifname n)
+ (concat [ rpc_argdecl TX ifname a | a <- args ])
+msg_argstruct dir ifname typedefs m@(Message _ n [] _) = C.NoOp
+msg_argstruct dir ifname typedefs m@(Message _ n args _) =
+ C.StructDecl (msg_argstruct_name dir ifname n)
+ (concat [ msg_argstructdecl dir ifname typedefs a | a <- args ])
--
-- Generate a union of all the above
--
-intf_union :: String -> [MessageDef] -> C.Unit
-intf_union ifn msgs =
- C.UnionDecl (binding_arg_union_type ifn)
- ([ C.Param (C.Struct $ msg_argstruct_name ifn n) n
+intf_union :: Direction -> String -> [MessageDef] -> C.Unit
+intf_union dir ifn msgs =
+ C.UnionDecl (binding_arg_union_type dir ifn)
+ ([ C.Param (C.Struct $ msg_argstruct_name dir ifn n) n
| m@(Message _ n a _) <- msgs, 0 /= length a ]
++
- [ C.Param (C.Struct $ msg_argstruct_name ifn n) n
+ [ C.Param (C.Struct $ msg_argstruct_name dir ifn n) n
| m@(RPC n a _) <- msgs, 0 /= length a ]
)
C.Param (C.Ptr C.Void) "st",
C.ParamBlank,
- C.ParamComment "Waitset used for receive handlers and send continuations",
+ C.ParamComment "Waitset used for receive handlers",
C.Param (C.Ptr $ C.Struct "waitset") "waitset",
C.ParamBlank,
C.Param (C.Ptr $ C.TypeName $ error_handler_fn_type n) "error_handler",
C.ParamBlank,
+ C.ParamComment "receive next message",
+ C.Param (C.Ptr $ C.TypeName $ receive_next_fn_type n) "receive_next",
+ C.ParamBlank,
+
+ C.ParamComment "get receiving chanstate",
+ C.Param (C.Ptr $ C.TypeName $ get_receiving_chanstate_fn_type n) "get_receiving_chanstate",
+ C.ParamBlank,
+
C.ParamComment "Message send functions (filled in by binding)",
C.Param (C.Struct $ intf_vtbl_type n TX) "tx_vtbl",
C.ParamBlank,
- C.ParamComment "Incoming message handlers (filled in by user)",
+ C.ParamComment "Incoming message handlers, direct (filled in by user)",
C.Param (C.Struct $ intf_vtbl_type n RX) "rx_vtbl",
C.ParamBlank,
+ C.ParamComment "Incoming message handlers, indirect (filled in by user)",
+ C.Param (C.Struct $ intf_vtbl_type n RX) "message_rx_vtbl",
+ C.ParamBlank,
+
+ C.ParamComment "Incoming message rpc handlers (filled in by user)",
+ C.Param (C.Struct $ rpc_rx_vtbl_type n) "rpc_rx_vtbl",
+ C.ParamBlank,
+
+ C.ParamComment "Message channels",
+ C.Param (C.Array (toInteger ((length ml) + 3)) (C.Struct "waitset_chanstate")) "message_chanstate",
+
+ C.ParamComment "Waitset used for send continuations",
+ C.Param (C.Ptr $ C.Struct "waitset") "send_waitset",
+ C.ParamBlank,
+
C.ParamComment "Private state belonging to the binding implementation",
- C.Param (C.Union $ binding_arg_union_type n) "tx_union",
- C.Param (C.Union $ binding_arg_union_type n) "rx_union",
+ C.Param (C.Union $ binding_arg_union_type TX n) "tx_union",
+ C.Param (C.Union $ binding_arg_union_type RX n) "rx_union",
C.Param (C.Struct "waitset_chanstate") "register_chanstate",
C.Param (C.Struct "waitset_chanstate") "tx_cont_chanstate",
C.Param (C.Enum $ msg_enum_name n) "tx_msgnum",
C.Param (C.TypeName "size_t") "tx_str_len",
C.Param (C.TypeName "size_t") "rx_str_len",
C.Param (C.Struct "event_queue_node") "event_qnode",
- C.Param (C.Ptr $ C.TypeName $ intf_bind_cont_type n) "bind_cont"]
+ C.Param (C.Ptr $ C.TypeName $ intf_bind_cont_type n) "bind_cont",
+ C.Param (C.TypeName "uint32_t") "incoming_token",
+ C.Param (C.TypeName "uint32_t") "outgoing_token",
+ C.Param (C.Struct "thread_mutex") "rxtx_mutex",
+ C.Param (C.Struct "thread_mutex") "send_mutex",
+ C.Param (C.TypeName "errval_t") "error"
+ ]
--
-- Generate the binding structure
params = [ binding_param n,
C.Param (C.TypeName "errval_t") "err" ]
+receive_next_fn_typedef :: String -> C.Unit
+receive_next_fn_typedef n =
+ C.TypeDef
+ (C.Function C.NoScope (C.TypeName "errval_t") params)
+ (receive_next_fn_type n)
+ where
+ params = [binding_param n]
+
+get_receiving_chanstate_fn_typedef :: String -> C.Unit
+get_receiving_chanstate_fn_typedef n =
+ C.TypeDef
+ (C.Function C.NoScope (C.Ptr $ C.Struct "waitset_chanstate") params)
+ (get_receiving_chanstate_fn_type n)
+ where
+ params = [binding_param n]
+
bind_function :: String -> C.Unit
bind_function n =
C.GVarDecl C.Extern C.NonConst
payload_params = [ msg_argdecl TX ifn a | a <- args ]
payload_args = map C.Variable $ concat $ map mkargs args
mkargs (Arg _ (Name an)) = [an]
- mkargs (Arg _ (DynamicArray an al)) = [an, al]
+ mkargs (Arg _ (StringArray an _)) = [an]
+ mkargs (Arg _ (DynamicArray an al _)) = [an, al]
--
-- Include the right files for different backends
-{-
+{-
LMP.hs: Flounder stub generator for local message passing.
Part of Flounder: a message passing IDL for Barrelfish
-- Names of the control functions
change_waitset_fn_name ifn = ifscope ifn "lmp_change_waitset"
control_fn_name ifn = ifscope ifn "lmp_control"
+receive_next_fn_name ifn = ifscope ifn "lmp_receive_next"
+get_receiving_chanstate_fn_name ifn = ifscope ifn "lmp_get_receiving_chanstate"
------------------------------------------------------------------------
-- Language mapping: Create the header file for this interconnect driver
default_error_handler_fn_def drvname ifn,
change_waitset_fn_def ifn,
control_fn_def ifn,
+ receive_next_fn_def ifn,
+ get_receiving_chanstate_fn_def ifn,
C.MultiComment [ "Functions to initialise/destroy the binding state" ],
lmp_init_fn ifn,
C.Ex $ C.Call "lmp_chan_init" [C.AddressOf $ C.DerefField lmp_bind_var "chan"],
C.Ex $ C.Assignment (common_field "change_waitset") (C.Variable $ change_waitset_fn_name ifn),
C.Ex $ C.Assignment (common_field "control") (C.Variable $ control_fn_name ifn),
+ C.Ex $ C.Assignment (common_field "receive_next") (C.Variable $ receive_next_fn_name ifn),
+ C.Ex $ C.Assignment (common_field "get_receiving_chanstate") (C.Variable $ get_receiving_chanstate_fn_name ifn),
C.Ex $ C.Assignment
(C.DerefField lmp_bind_var "flags")
(C.Variable "LMP_SEND_FLAGS_DEFAULT") ]
C.Return $ errvar] [],
C.SBlank,
+ C.Ex $ C.Call (connect_handlers_fn_name ifn) [C.Variable intf_bind_var],
+ C.SBlank,
+
C.SComment "register for receive",
C.Ex $ C.Assignment errvar $ C.Call "lmp_chan_register_recv"
[chanaddr, C.DerefField bindvar "waitset",
C.Ex $ C.Call "flounder_support_migrate_notify" [register_chanstate, C.Variable "ws"],
C.Ex $ C.Call "flounder_support_migrate_notify" [tx_cont_chanstate, C.Variable "ws"],
C.SBlank,
+ C.Ex $ C.Call (disconnect_handlers_fn_name ifn) [bindvar],
C.SComment "change waitset on binding",
C.Ex $ C.Assignment
(C.Variable "ws"),
C.SBlank,
+ C.Ex $ C.Call (connect_handlers_fn_name ifn) [bindvar],
+
C.SComment "Migrate send and receive notifications",
C.Ex $ C.Call "lmp_chan_migrate_recv" [chanaddr, C.Variable "ws"],
C.Ex $ C.Call "lmp_chan_migrate_send" [chanaddr, C.Variable "ws"],
params = [C.Param (C.Ptr $ C.Struct $ intf_bind_type ifn) intf_bind_var,
C.Param (C.TypeName "idc_control_t") "control"]
+receive_next_fn_def :: String -> C.Unit
+receive_next_fn_def ifn =
+ C.FunctionDef C.Static (C.TypeName "errval_t") (receive_next_fn_name ifn) params [
+ localvar (C.TypeName "errval_t") "err" Nothing,
+ localvar (C.Ptr $ C.Struct $ lmp_bind_type ifn)
+ lmp_bind_var_name (Just $ C.Cast (C.Ptr C.Void) $ C.Variable intf_bind_var),
+ localvar (C.Struct "event_closure") "recv_closure"
+ (Just $ C.StructConstant "event_closure" [
+ ("handler", C.Variable $ rx_handler_name ifn),
+ ("arg", C.Variable intf_bind_var)]),
+ C.SBlank,
+ C.SComment "register for another receive notification",
+ C.Ex $ C.Assignment errvar $ C.Call "lmp_chan_register_recv"
+ [chanaddr, C.DerefField bindvar "waitset", C.Variable "recv_closure"],
+ C.Ex $ C.Call "assert" [C.Call "err_is_ok" [errvar]],
+ C.Return $ C.Variable "SYS_ERR_OK"
+ ]
+ where
+ params = [C.Param (C.Ptr $ C.Struct $ intf_bind_type ifn) intf_bind_var]
+ chanaddr = C.AddressOf $ C.DerefField lmp_bind_var "chan"
+
+get_receiving_chanstate_fn_def :: String -> C.Unit
+get_receiving_chanstate_fn_def ifn =
+ C.FunctionDef C.Static (C.Ptr $ C.Struct "waitset_chanstate") (get_receiving_chanstate_fn_name ifn) params [
+ localvar (C.Ptr $ C.Struct $ lmp_bind_type ifn)
+ lmp_bind_var_name (Just $ C.Cast (C.Ptr C.Void) $ C.Variable intf_bind_var),
+ C.SBlank,
+ C.Return $ C.Call "lmp_chan_get_receiving_channel" [C.AddressOf $ C.DerefField lmp_bind_var "chan"]
+ ]
+ where
+ params = [C.Param (C.Ptr $ C.Struct $ intf_bind_type ifn) intf_bind_var]
+
handler_preamble :: String -> C.Stmt
handler_preamble ifn = C.StmtList
[C.SComment "Get the binding state from our argument pointer",
pos_arg = C.AddressOf $ C.DerefField bindvar "tx_str_pos"
tx_fn :: String -> [TypeDef] -> MessageDef -> C.Unit
-tx_fn ifn typedefs msg@(Message _ n args _) =
+tx_fn ifn typedefs msg@(Message mtype n args _) =
C.FunctionDef C.Static (C.TypeName "errval_t") (tx_fn_name ifn n) params body
where
params = [binding_param ifn, cont_param] ++ (
concat [ msg_argdecl TX ifn a | a <- args ])
cont_param = C.Param (C.Struct "event_closure") intf_cont_var
body = [
+ -- check size of message
+ C.StmtList [ tx_fn_arg_check_size ifn typedefs n a | a <- args ],
C.SComment "check that we can accept an outgoing message",
+ C.Ex $ C.Call "thread_mutex_lock" [C.AddressOf $ C.DerefField bindvar "send_mutex"],
+ localvar (C.Ptr $ C.Struct "waitset") "send_waitset" (Just $ C.DerefField bindvar "waitset"),
+ C.Ex $ C.Assignment binding_error (C.Variable "SYS_ERR_OK"),
C.If (C.Binary C.NotEquals tx_msgnum_field (C.NumConstant 0))
- [C.Return $ C.Variable "FLOUNDER_ERR_TX_BUSY"] [],
+ [C.Ex $ C.Call "thread_mutex_unlock" [C.AddressOf $ C.DerefField bindvar "send_mutex"],
+ C.Return $ C.Variable "FLOUNDER_ERR_TX_BUSY"] [],
C.SBlank,
C.SComment "register send continuation",
C.StmtList $ register_txcont (C.Variable intf_cont_var),
C.SBlank,
C.SComment "store message number and arguments",
+ C.Ex $ C.Assignment binding_outgoing_token (C.Binary C.BitwiseAnd binding_incoming_token (C.Variable "~1" )),
+ C.Ex $ C.Call "thread_get_outgoing_token" [C.AddressOf binding_outgoing_token],
C.Ex $ C.Assignment tx_msgnum_field (C.Variable $ msg_enum_elem_name ifn n),
C.Ex $ C.Assignment tx_msgfrag_field (C.NumConstant 0),
C.StmtList [ tx_arg_assignment ifn typedefs n a | a <- args ],
C.SBlank,
C.SComment "try to send!",
C.Ex $ C.Call (tx_handler_name ifn n) [C.Variable intf_bind_var],
+ C.StmtList $ block_sending (C.Variable intf_cont_var),
+ C.Ex $ C.Call "thread_mutex_unlock" [C.AddressOf $ C.DerefField bindvar "send_mutex"],
C.SBlank,
- C.Return $ C.Variable "SYS_ERR_OK"
+ C.Return binding_error
]
tx_msgnum_field = C.DerefField bindvar "tx_msgnum"
tx_msgfrag_field = C.DerefField bindvar "tx_msg_fragment"
+ binding_incoming_token = C.DerefField bindvar "incoming_token"
+ binding_outgoing_token = C.DerefField bindvar "outgoing_token"
tx_vtbl :: String -> [MessageDef] -> C.Unit
tx_vtbl ifn ml =
handler_preamble ifn,
localvar (C.Struct "lmp_recv_msg") "msg" (Just $ C.Variable "LMP_RECV_MSG_INIT"),
localvar (C.Struct "capref") "cap" Nothing,
+ localvar (C.TypeName "int") "__attribute__ ((unused)) no_register" (Just $ C.NumConstant 0),
-- declare closure for retry
localvar (C.Struct "event_closure") "recv_closure"
("arg", C.Variable "arg")]),
C.SBlank,
+ C.If (C.Unary C.Not $ C.Call "lmp_chan_can_recv" [chanaddr]) [C.Goto "out"] [],
+
C.DoWhile (C.Call "err_is_ok" [errvar]) [
C.SComment "try to retrieve a message from the channel",
-- if err_is_fail, check err_no
[C.If (C.Binary C.Equals (C.Call "err_no" [errvar]) (C.Variable "LIB_ERR_NO_LMP_MSG"))
[C.SComment "no message",
- C.Break]
+ C.Ex $ C.Assignment errvar $ C.Variable "SYS_ERR_OK",
+ C.Continue]
[C.SComment "real error",
report_user_err $ C.Call "err_push" [errvar, C.Variable "LIB_ERR_LMP_CHAN_RECV"],
C.ReturnVoid]
], -- end of the while(1) loop
C.Label "out",
- C.SComment "re-register for another receive notification",
- C.Ex $ C.Assignment errvar $ C.Call "lmp_chan_register_recv"
- [chanaddr, C.DerefField bindvar "waitset", C.Variable "recv_closure"],
- C.Ex $ C.Call "assert" [C.Call "err_is_ok" [errvar]]
+ C.If (C.Unary C.Not (C.Variable "no_register"))
+ [C.SComment "re-register for another receive notification",
+ C.Ex $ C.Assignment errvar $ C.Call "lmp_chan_register_recv"
+ [chanaddr, C.DerefField bindvar "waitset", C.Variable "recv_closure"],
+ C.Ex $ C.Call "assert" [C.Call "err_is_ok" [errvar]]]
+ []
]
where
chanaddr = C.AddressOf $ C.DerefField lmp_bind_var "chan"
msgnum_bits = bitsizeof_argfieldfrag arch MsgCode
rx_msgnum_field = C.DerefField bindvar "rx_msgnum"
rx_msgfrag_field = C.DerefField bindvar "rx_msg_fragment"
+ binding_incoming_token = C.DerefField bindvar "incoming_token"
msgnum_cases = [C.Case (C.Variable $ msg_enum_elem_name ifn mn) (msgnum_case msgdef msg)
| (msgdef, msg@(LMPMsgSpec mn _)) <- zip msgdefs msgs]
],
C.Break]
where
- args = [msg_arg, string_arg, pos_arg, len_arg]
+ args = [msg_arg, string_arg, pos_arg, len_arg, maxsize]
msg_arg = C.AddressOf $ C.Variable "msg"
- string_arg = C.AddressOf $ argfield_expr RX mn af
+ string_arg = argfield_expr RX mn af
pos_arg = C.AddressOf $ C.DerefField bindvar "rx_str_pos"
len_arg = C.AddressOf $ C.DerefField bindvar "rx_str_len"
+ maxsize = C.SizeOf $ string_arg
msgfrag_case msg@(Message _ mn _ _) (LMPMsgFragment (OverflowFragment (BufferFragment _ afn afl)) _) isLast = [
C.Ex $ C.Assignment errvar (C.Call "flounder_stub_lmp_recv_buf" args),
],
C.Break]
where
- args = [msg_arg, buf_arg, len_arg, pos_arg]
+ args = [msg_arg, buf_arg, len_arg, pos_arg, maxsize]
msg_arg = C.AddressOf $ C.Variable "msg"
- buf_arg = C.Cast (C.Ptr $ C.Ptr C.Void) $ C.AddressOf $ argfield_expr RX mn afn
+ buf_arg = C.Cast (C.Ptr C.Void) $ argfield_expr RX mn afn
len_arg = C.AddressOf $ argfield_expr RX mn afl
pos_arg = C.AddressOf $ C.DerefField bindvar "rx_str_pos"
+ maxsize = C.SizeOf $ argfield_expr RX mn afn
msgfrag_case_prolog :: MessageDef -> Bool -> C.Stmt
-- intermediate fragment
= C.Ex $ C.PostInc $ C.DerefField bindvar "rx_msg_fragment"
-- last fragment: call handler and zero message number
- msgfrag_case_prolog (Message _ mn msgargs _) True
- = C.StmtList $ finished_recv drvname ifn typedefs mn msgargs
+ msgfrag_case_prolog (Message mtype mn msgargs _) True
+ = C.StmtList [
+ C.StmtList $ (finished_recv drvname ifn typedefs mtype mn msgargs),
+ C.Goto "out"
+ ]
+ where
+ lmp_chan = C.AddressOf $ C.DerefField lmp_bind_var "chan"
-{-
+{-
Loopback.hs: Flounder stub generator for dummy loopback stubs
Part of Flounder: a message passing IDL for Barrelfish
C.Return $ C.Variable "SYS_ERR_OK"
]
- arrayargs = [a | a@(Arg _ (DynamicArray _ _)) <- args]
+ arrayargs = [a | a@(Arg _ (DynamicArray _ _ _)) <- args]
- copyarray (Arg tr (DynamicArray n l)) = [
+ copyarray (Arg tr (DynamicArray n l _)) = [
localvar array_type (array_copy_name n)
$ Just $ C.Call "malloc" [size],
C.If (C.Binary C.Equals copyvar (C.Variable "NULL"))
-- string and array arguments need special treatment
mkvars (Arg (Builtin String) (Name n)) = [C.Call "strdup" [C.Variable n]]
- mkvars (Arg _ (DynamicArray n l)) = [C.Variable $ array_copy_name n, C.Variable l]
+ mkvars (Arg _ (DynamicArray n l _)) = [C.Variable $ array_copy_name n, C.Variable l]
mkvars (Arg _ (Name n)) = [C.Variable n]
array_copy_name n = "_copy_of_" ++ n
> import System.FilePath.Posix
> import Data.Maybe
> import Control.Monad
+> import Data.Eq
> import Text.ParserCombinators.Parsec as Parsec
> import qualified Parser
> data Target = GenericHeader
> | GenericCode
+> | MessageHandlers
> | LMP_Header
> | LMP_Stub
> | UMP_Header
> | UMP_Stub
> | UMP_IPI_Header
> | UMP_IPI_Stub
-> | Multihop_Stub
+> | Multihop_Stub
> | Multihop_Header
> | Loopback_Header
> | Loopback_Stub
> | THCStubs
> | AHCI_Header
> | AHCI_Stub
-> deriving (Show)
+> deriving (Show, Eq)
> data Options = Options {
> optTargets :: [Target],
> generator :: Options -> Target -> String -> String -> Syntax.Interface -> String
> generator _ GenericHeader = GHBackend.compile
> generator _ GenericCode = GCBackend.compile
+> generator _ MessageHandlers = GCBa