diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 871dc1b9f..fdfbff2e2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,20 +20,20 @@ jobs: cmake-args: '-DNUMBER_OF_WORKERS=4' fetch-lf: - uses: lf-lang/lingua-franca/.github/workflows/extract-ref.yml@master + uses: lf-lang/lingua-franca/.github/workflows/extract-ref.yml@set-destructor-variant with: file: 'lingua-franca-ref.txt' lf-default: needs: fetch-lf - uses: lf-lang/lingua-franca/.github/workflows/c-tests.yml@master + uses: lf-lang/lingua-franca/.github/workflows/c-tests.yml@set-destructor-variant with: runtime-ref: ${{ github.ref }} compiler-ref: ${{ needs.fetch-lf.outputs.ref }} lf-gedf-np: needs: fetch-lf - uses: lf-lang/lingua-franca/.github/workflows/c-tests.yml@master + uses: lf-lang/lingua-franca/.github/workflows/c-tests.yml@set-destructor-variant with: runtime-ref: ${{ github.ref }} compiler-ref: ${{ needs.fetch-lf.outputs.ref }} @@ -41,7 +41,7 @@ jobs: lf-gedf-np-ci: needs: fetch-lf - uses: lf-lang/lingua-franca/.github/workflows/c-tests.yml@master + uses: lf-lang/lingua-franca/.github/workflows/c-tests.yml@set-destructor-variant with: runtime-ref: ${{ github.ref }} compiler-ref: ${{ needs.fetch-lf.outputs.ref }} diff --git a/core/federated/RTI/rti.c b/core/federated/RTI/rti.c index 1f0d693dd..6a580e585 100644 --- a/core/federated/RTI/rti.c +++ b/core/federated/RTI/rti.c @@ -339,7 +339,7 @@ void handle_timed_message(federate_t* sending_federate, unsigned char* buffer) { // is a promise that is valid only in the absence of network inputs, // and now there is a network input. Hence, the promise needs to be // updated. - if (compare_tags(_RTI.federates[federate_id].next_event, intended_tag) > 0) { + if (lf_compare_tags(_RTI.federates[federate_id].next_event, intended_tag) > 0) { _RTI.federates[federate_id].next_event = intended_tag; } @@ -400,8 +400,8 @@ void handle_timed_message(federate_t* sending_federate, unsigned char* buffer) { */ void send_tag_advance_grant(federate_t* fed, tag_t tag) { if (fed->state == NOT_CONNECTED - || compare_tags(tag, fed->last_granted) <= 0 - || compare_tags(tag, fed->last_provisionally_granted) < 0 + || lf_compare_tags(tag, fed->last_granted) <= 0 + || lf_compare_tags(tag, fed->last_provisionally_granted) < 0 ) { return; } @@ -463,7 +463,7 @@ tag_t transitive_next_event(federate_t* fed, tag_t candidate, bool visited[]) { tag_t result = fed->next_event; // If the candidate is less than this federate's next_event, use the candidate. - if (compare_tags(candidate, result) < 0) { + if (lf_compare_tags(candidate, result) < 0) { result = candidate; } @@ -480,14 +480,14 @@ tag_t transitive_next_event(federate_t* fed, tag_t candidate, bool visited[]) { &_RTI.federates[fed->upstream[i]], result, visited); // Add the "after" delay of the connection to the result. - upstream_result = delay_tag(upstream_result, fed->upstream_delay[i]); + upstream_result = _lf_delay_tag(upstream_result, fed->upstream_delay[i]); // If the adjusted event time is less than the result so far, update the result. - if (compare_tags(upstream_result, result) < 0) { + if (lf_compare_tags(upstream_result, result) < 0) { result = upstream_result; } } - if (compare_tags(result, fed->completed) < 0) { + if (lf_compare_tags(result, fed->completed) < 0) { result = fed->completed; } return result; @@ -507,8 +507,8 @@ tag_t transitive_next_event(federate_t* fed, tag_t candidate, bool visited[]) { */ void send_provisional_tag_advance_grant(federate_t* fed, tag_t tag) { if (fed->state == NOT_CONNECTED - || compare_tags(tag, fed->last_granted) <= 0 - || compare_tags(tag, fed->last_provisionally_granted) <= 0 + || lf_compare_tags(tag, fed->last_granted) <= 0 + || lf_compare_tags(tag, fed->last_provisionally_granted) <= 0 || (tag.time == start_time && tag.microstep == 0) // PTAG at (0,0) is implicit ) { return; @@ -558,7 +558,7 @@ void send_provisional_tag_advance_grant(federate_t* fed, tag_t tag) { // a TAG or PTAG should have already been granted, // in which case, another will not be sent. But it // may not have been already granted. - if (compare_tags(upstream_next_event, tag) >= 0) { + if (lf_compare_tags(upstream_next_event, tag) >= 0) { send_provisional_tag_advance_grant(upstream, tag); } } @@ -605,9 +605,9 @@ bool send_advance_grant_if_safe(federate_t* fed) { // Ignore this federate if it has resigned. if (upstream->state == NOT_CONNECTED) continue; - tag_t candidate = delay_tag(upstream->completed, fed->upstream_delay[j]); + tag_t candidate = _lf_delay_tag(upstream->completed, fed->upstream_delay[j]); - if (compare_tags(candidate, min_upstream_completed) < 0) { + if (lf_compare_tags(candidate, min_upstream_completed) < 0) { min_upstream_completed = candidate; } } @@ -615,7 +615,7 @@ bool send_advance_grant_if_safe(federate_t* fed) { "(adjusted by after delay).", fed->id, min_upstream_completed.time - start_time, min_upstream_completed.microstep); - if (compare_tags(min_upstream_completed, fed->last_granted) > 0) { + if (lf_compare_tags(min_upstream_completed, fed->last_granted) > 0) { send_tag_advance_grant(fed, min_upstream_completed); return true; } @@ -656,9 +656,9 @@ bool send_advance_grant_if_safe(federate_t* fed) { // Adjust by the "after" delay. // Note that "no delay" is encoded as NEVER, // whereas one microstep delay is encoded as 0LL. - tag_t candidate = delay_tag(upstream_next_event, fed->upstream_delay[j]); + tag_t candidate = _lf_delay_tag(upstream_next_event, fed->upstream_delay[j]); - if (compare_tags(candidate, t_d) < 0) { + if (lf_compare_tags(candidate, t_d) < 0) { t_d = candidate; } } @@ -666,7 +666,7 @@ bool send_advance_grant_if_safe(federate_t* fed) { LOG_PRINT("Earliest next event upstream has tag (%lld, %u).", t_d.time - start_time, t_d.microstep); - if (compare_tags(t_d, FOREVER_TAG) == 0) { + if (lf_compare_tags(t_d, FOREVER_TAG) == 0) { // Upstream federates are all done. LOG_PRINT("Upstream federates are all done. Granting tag advance."); send_tag_advance_grant(fed, FOREVER_TAG); @@ -678,9 +678,9 @@ bool send_advance_grant_if_safe(federate_t* fed) { send_tag_advance_grant(fed, FOREVER_TAG); return true; } else if ( - compare_tags(t_d, fed->next_event) >= 0 // The federate has something to do. - && compare_tags(t_d, fed->last_provisionally_granted) > 0 // The grant is not redundant. - && compare_tags(t_d, fed->last_granted) > 0 // The grant is not redundant. + lf_compare_tags(t_d, fed->next_event) >= 0 // The federate has something to do. + && lf_compare_tags(t_d, fed->last_provisionally_granted) > 0 // The grant is not redundant. + && lf_compare_tags(t_d, fed->last_granted) > 0 // The grant is not redundant. ) { LOG_PRINT("Earliest upstream message time for fed %d is (%lld, %u) " "(adjusted by after delay). Granting provisional tag advance.", @@ -812,7 +812,7 @@ void handle_time_advance_notice(federate_t* fed) { // network inputs, the federate will not produce an output with tag // less than the NET. tag_t ta = (tag_t) {.time = fed->time_advance, .microstep = 0}; - if (compare_tags(ta, fed->next_event) > 0) { + if (lf_compare_tags(ta, fed->next_event) > 0) { fed->next_event = ta; // We need to reply just as if this were a NET because it could unblock // network input port control reactions. @@ -860,7 +860,7 @@ void _lf_rti_broadcast_stop_time_to_federates_already_locked() { if (_RTI.federates[i].state == NOT_CONNECTED) { continue; } - if (compare_tags(_RTI.federates[i].next_event, _RTI.max_stop_tag) >= 0) { + if (lf_compare_tags(_RTI.federates[i].next_event, _RTI.max_stop_tag) >= 0) { // Need the next_event to be no greater than the stop tag. _RTI.federates[i].next_event = _RTI.max_stop_tag; } @@ -930,7 +930,7 @@ void handle_stop_request_message(federate_t* fed) { tag_t proposed_stop_tag = extract_tag(buffer); // Update the maximum stop tag received from federates - if (compare_tags(proposed_stop_tag, _RTI.max_stop_tag) > 0) { + if (lf_compare_tags(proposed_stop_tag, _RTI.max_stop_tag) > 0) { _RTI.max_stop_tag = proposed_stop_tag; } @@ -993,7 +993,7 @@ void handle_stop_request_reply(federate_t* fed) { // Acquire the mutex lock so that we can change the state of the RTI pthread_mutex_lock(&_RTI.rti_mutex); // If the federate has not requested stop before, count the reply - if (compare_tags(federate_stop_tag, _RTI.max_stop_tag) > 0) { + if (lf_compare_tags(federate_stop_tag, _RTI.max_stop_tag) > 0) { _RTI.max_stop_tag = federate_stop_tag; } mark_federate_requesting_stop(fed); @@ -1163,7 +1163,7 @@ void send_physical_clock(unsigned char message_type, federate_t* fed, socket_typ } unsigned char buffer[sizeof(int64_t) + 1]; buffer[0] = message_type; - int64_t current_physical_time = get_physical_time(); + int64_t current_physical_time = lf_time(LF_PHYSICAL); encode_int64(current_physical_time, &(buffer[1])); // Send the message @@ -1240,7 +1240,7 @@ void* clock_synchronization_thread(void* noargs) { // Wait until the start time before starting clock synchronization. // The above wait ensures that start_time has been set. - interval_t ns_to_wait = start_time - get_physical_time(); + interval_t ns_to_wait = start_time - lf_time(LF_PHYSICAL); if (ns_to_wait > 0LL) { struct timespec wait_time = {ns_to_wait / BILLION, ns_to_wait % BILLION}; diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index cad04161b..65dc2aa3a 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -218,7 +218,7 @@ void synchronize_initial_physical_clock_with_rti(int rti_socket_TCP) { _lf_my_fed_id); // Get local physical time before doing anything else. - instant_t receive_time = get_physical_time(); + instant_t receive_time = lf_time(LF_PHYSICAL); // Check that this is the T1 message. if (buffer[0] != MSG_TYPE_CLOCK_SYNC_T1) { @@ -287,7 +287,7 @@ int handle_T1_clock_sync_message(unsigned char* buffer, int socket, instant_t t2 // Measure the time _after_ the write on the assumption that the read // from the socket, which occurs before this function is called, takes // about the same amount of time as the write of the reply. - _lf_rti_socket_stat.local_delay = get_physical_time() - t2; + _lf_rti_socket_stat.local_delay = lf_time(LF_PHYSICAL) - t2; return 0; } @@ -346,7 +346,7 @@ void handle_T4_clock_sync_message(unsigned char* buffer, int socket, instant_t r // We can reuse the same buffer. ssize_t bytes_read = read_from_socket(socket, 1 + sizeof(instant_t), buffer); - instant_t r5 = get_physical_time(); + instant_t r5 = lf_time(LF_PHYSICAL); if ((bytes_read < 1 + (ssize_t)sizeof(instant_t)) || buffer[0] != MSG_TYPE_CLOCK_SYNC_CODED_PROBE) { @@ -380,7 +380,7 @@ void handle_T4_clock_sync_message(unsigned char* buffer, int socket, instant_t r } // Apply a jitter attenuator to the estimated clock error to prevent // large jumps in the underlying clock. - // Note that estimated_clock_error is calculated using get_physical_time() which includes + // Note that estimated_clock_error is calculated using lf_time(LF_PHYSICAL) which includes // the _lf_global_physical_clock_offset adjustment. adjustment = estimated_clock_error / _LF_CLOCK_SYNC_ATTENUATION; @@ -485,7 +485,7 @@ void* listen_to_rti_UDP_thread(void* args) { } while ((errno == EAGAIN || errno == EWOULDBLOCK) && bytes_read < message_size); // Get local physical time before doing anything else. - instant_t receive_time = get_physical_time(); + instant_t receive_time = lf_time(LF_PHYSICAL); if (bytes_read < message_size) { // Either the socket has closed or the RTI has sent EOF. diff --git a/core/federated/federate.c b/core/federated/federate.c index 3a8ebf9fa..7377e0ea9 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -371,7 +371,7 @@ int send_timed_message(interval_t additional_delay, // Apply the additional delay to the current tag and use that as the intended // tag of the outgoing message - tag_t current_message_intended_tag = delay_tag(get_current_tag(), + tag_t current_message_intended_tag = _lf_delay_tag(lf_tag(), additional_delay); // Next 8 + 4 will be the tag (timestamp, microstep) @@ -1062,7 +1062,7 @@ instant_t get_start_time_from_rti(instant_t my_physical_time) { instant_t timestamp = extract_int64(&(buffer[1])); info_print("Starting timestamp is: %lld.", timestamp); - LOG_PRINT("Current physical time is: %lld.", get_physical_time()); + LOG_PRINT("Current physical time is: %lld.", lf_time(LF_PHYSICAL)); return timestamp; } @@ -1140,7 +1140,7 @@ void update_last_known_status_on_input_ports(tag_t tag) { // connection), in which case, the last known status tag of the port // is in the future and should not be rolled back. So in that case, // we do not update the last known status tag. - if (compare_tags(tag, + if (lf_compare_tags(tag, input_port_action->last_known_status_tag) >= 0) { input_port_action->last_known_status_tag = tag; if (input_port_action->is_a_control_reaction_waiting) { @@ -1174,12 +1174,12 @@ void update_last_known_status_on_input_ports(tag_t tag) { */ void update_last_known_status_on_input_port(tag_t tag, int port_id) { trigger_t* input_port_action = _lf_action_for_port(port_id); - if (compare_tags(tag, + if (lf_compare_tags(tag, input_port_action->last_known_status_tag) >= 0) { - if (compare_tags(tag, + if (lf_compare_tags(tag, input_port_action->last_known_status_tag) == 0) { // If the intended tag for an input port is equal to the last known status, we need - // to increment the microstep. This is a direct result of the behavior of the delay_tag() + // to increment the microstep. This is a direct result of the behavior of the _lf_delay_tag() // semantics in tag.h. tag.microstep++; } @@ -1233,13 +1233,13 @@ port_status_t get_current_port_status(int portID) { // The status of the trigger is absent. return absent; } else if (network_input_port_action->status == unknown - && compare_tags(network_input_port_action->last_known_status_tag, get_current_tag()) >= 0) { + && lf_compare_tags(network_input_port_action->last_known_status_tag, lf_tag()) >= 0) { // We have a known status for this port in a future tag. Therefore, no event is going // to be present for this port at the current tag. set_network_port_status(portID, absent); return absent; } else if (_fed.is_last_TAG_provisional - && compare_tags(_fed.last_TAG, get_current_tag()) > 0) { + && lf_compare_tags(_fed.last_TAG, lf_tag()) > 0) { // In this case, a PTAG has been received with a larger tag than the current tag, // which means that the input port is known to be absent. set_network_port_status(portID, absent); @@ -1298,7 +1298,7 @@ void enqueue_network_control_reactions() { #ifdef FEDERATED_CENTRALIZED // If the granted tag is not provisional, there is no // need for network input control reactions - if (compare_tags(_fed.last_TAG, get_current_tag()) != 0 + if (lf_compare_tags(_fed.last_TAG, lf_tag()) != 0 || _fed.is_last_TAG_provisional == false) { return; } @@ -1327,7 +1327,7 @@ void send_port_absent_to_federate(interval_t additional_delay, // Apply the additional delay to the current tag and use that as the intended // tag of the outgoing message - tag_t current_message_intended_tag = delay_tag(get_current_tag(), + tag_t current_message_intended_tag = _lf_delay_tag(lf_tag(), additional_delay); LOG_PRINT("Sending port " @@ -1431,7 +1431,7 @@ void wait_until_port_status_known(int port_ID, interval_t STP) { // for the current tag could have been received in time // but not the the body of the message. // Wait on the tag barrier based on the current tag. - _lf_wait_on_global_tag_barrier(get_current_tag()); + _lf_wait_on_global_tag_barrier(lf_tag()); // Done waiting // If the status of the port is still unknown, assume it is absent. @@ -1482,7 +1482,7 @@ trigger_handle_t schedule_message_received_from_network_already_locked( // of the message (timestamp, microstep) is // in the future relative to the tag of this // federate. By default, assume it is not. - bool message_tag_is_in_the_future = compare_tags(tag, current_tag) > 0; + bool message_tag_is_in_the_future = lf_compare_tags(tag, current_tag) > 0; // Assign the intended tag trigger->intended_tag = tag; @@ -1499,7 +1499,7 @@ trigger_handle_t schedule_message_received_from_network_already_locked( error_print_and_exit("Received a message at tag (%lld, %u) that" " has a tag (%lld, %u) that has violated the STP offset. " "Centralized coordination should not have these types of messages.", - current_tag.time - start_time, get_microstep(), + current_tag.time - start_time, lf_tag().microstep, tag.time - start_time, tag.microstep); #else // Set the delay back to 0 @@ -1513,7 +1513,7 @@ trigger_handle_t schedule_message_received_from_network_already_locked( // In case the message is in the future, call // _lf_schedule_at_tag() so that the microstep is respected. LOG_PRINT("Received a message that is (%lld nanoseconds, %u microsteps) " - "in the future.", extra_delay, tag.microstep - get_microstep()); + "in the future.", extra_delay, tag.microstep - lf_tag().microstep); return_value = _lf_schedule_at_tag(trigger, tag, token); } // Notify the main thread in case it is waiting for physical time to elapse. @@ -1610,7 +1610,7 @@ void handle_port_absent_message(int socket, int fed_id) { lf_mutex_lock(&mutex); #ifdef FEDERATED_DECENTRALIZED trigger_t* network_input_port_action = _lf_action_for_port(port_id); - if (compare_tags(intended_tag, + if (lf_compare_tags(intended_tag, network_input_port_action->last_known_status_tag) < 0) { lf_mutex_unlock(&mutex); error_print_and_exit("The following contract was violated for port absent messages: In-order " @@ -1708,7 +1708,7 @@ void handle_tagged_message(int socket, int fed_id) { trigger_t* action = _lf_action_for_port(port_id); // Record the physical time of arrival of the message - action->physical_time_of_arrival = get_physical_time(); + action->physical_time_of_arrival = lf_time(LF_PHYSICAL); if (action->is_physical) { // Messages sent on physical connections should be handled via handle_message(). @@ -1726,7 +1726,7 @@ void handle_tagged_message(int socket, int fed_id) { _lf_increment_global_tag_barrier(intended_tag); #endif LOG_PRINT("Received message with tag: (%lld, %u), Current tag: (%lld, %u).", - intended_tag.time - start_time, intended_tag.microstep, get_elapsed_logical_time(), get_microstep()); + intended_tag.time - start_time, intended_tag.microstep, lf_time(LF_ELAPSED_LOGICAL), lf_tag().microstep); // Read the payload. // Allocate memory for the message contents. @@ -1748,7 +1748,7 @@ void handle_tagged_message(int socket, int fed_id) { // Sanity checks #ifdef FEDERATED_DECENTRALIZED - if (compare_tags(intended_tag, + if (lf_compare_tags(intended_tag, action->last_known_status_tag) < 0) { error_print_and_exit("The following contract was violated for a timed message: In-order " "delivery of messages over a TCP socket. Had status for (%lld, %u), got " @@ -1782,7 +1782,7 @@ void handle_tagged_message(int socket, int fed_id) { // to exit. The port status is on the other hand changed in this thread, and thus, // can be checked in this scenario without this race condition. The message with // intended_tag of 9 in this case needs to wait one microstep to be processed. - if (compare_tags(intended_tag, get_current_tag()) <= 0 && + if (lf_compare_tags(intended_tag, lf_tag()) <= 0 && action->is_a_control_reaction_waiting && // Check if a control reaction is waiting action->status == unknown // Check if the status of the port is still unknown ) { @@ -1807,7 +1807,7 @@ void handle_tagged_message(int socket, int fed_id) { // Before that, if the current time >= stop time, discard the message. // But only if the stop time is not equal to the start time! - if (compare_tags(current_tag, stop_tag) >= 0) { + if (lf_compare_tags(current_tag, stop_tag) >= 0) { lf_mutex_unlock(&mutex); warning_print("Received message too late. Already at stopping time. Discarding message."); return; @@ -1865,7 +1865,7 @@ void handle_tag_advance_grant() { // It is possible for this federate to have received a PTAG // earlier with the same tag as this TAG. - if (compare_tags(TAG, _fed.last_TAG) >= 0) { + if (lf_compare_tags(TAG, _fed.last_TAG) >= 0) { _fed.last_TAG.time = TAG.time; _fed.last_TAG.microstep = TAG.microstep; _fed.is_last_TAG_provisional = false; @@ -1894,7 +1894,7 @@ void handle_tag_advance_grant() { * @param tag_to_send The tag to send. */ void _lf_logical_tag_complete(tag_t tag_to_send) { - int compare_with_last_tag = compare_tags(_fed.last_sent_LTC, tag_to_send); + int compare_with_last_tag = lf_compare_tags(_fed.last_sent_LTC, tag_to_send); if (compare_with_last_tag >= 0) { return; } @@ -1937,8 +1937,8 @@ void handle_provisional_tag_advance_grant() { lf_mutex_lock(&mutex); // Sanity check - if (compare_tags(PTAG, _fed.last_TAG) < 0 - || (compare_tags(PTAG, _fed.last_TAG) == 0 && !_fed.is_last_TAG_provisional)) { + if (lf_compare_tags(PTAG, _fed.last_TAG) < 0 + || (lf_compare_tags(PTAG, _fed.last_TAG) == 0 && !_fed.is_last_TAG_provisional)) { lf_mutex_unlock(&mutex); error_print_and_exit("Received a PTAG (%lld, %d) that is equal or earlier " "than an already received TAG (%lld, %d).", @@ -1972,7 +1972,7 @@ void handle_provisional_tag_advance_grant() { instant_t dummy_event_time = PTAG.time; microstep_t dummy_event_relative_microstep = PTAG.microstep; - if (compare_tags(current_tag, PTAG) == 0) { + if (lf_compare_tags(current_tag, PTAG) == 0) { // The current tag can equal the PTAG if we are at the start time // or if this federate has been able to advance time to the current // tag (e.g., it has no upstream federates). In either case, either @@ -1981,7 +1981,7 @@ void handle_provisional_tag_advance_grant() { // a LTC message shortly. In either case, there is nothing more to do. lf_mutex_unlock(&mutex); return; - } else if (compare_tags(current_tag, PTAG) > 0) { + } else if (lf_compare_tags(current_tag, PTAG) > 0) { // Current tag is greater than the PTAG. // It could be that we have sent an LTC that crossed with the incoming // PTAG or that we have advanced to a tag greater than the PTAG. @@ -2077,8 +2077,8 @@ void handle_stop_granted_message() { received_stop_tag.time - start_time, received_stop_tag.microstep); // Sanity check. - tag_t current_tag = get_current_tag(); - if (compare_tags(received_stop_tag, current_tag) <= 0) { + tag_t current_tag = lf_tag(); + if (lf_compare_tags(received_stop_tag, current_tag) <= 0) { error_print("RTI granted a MSG_TYPE_STOP_GRANTED tag that is equal to or less than this federate's current tag (%lld, %u). " "Stopping at the next microstep instead.", current_tag.time - start_time, current_tag.microstep); @@ -2129,7 +2129,7 @@ void handle_stop_request_message() { // Encode the current logical time plus one microstep // or the requested tag_to_stop, whichever is bigger. - if (compare_tags(tag_to_stop, current_tag) <= 0) { + if (lf_compare_tags(tag_to_stop, current_tag) <= 0) { // Can't stop at the requested tag. Make a counteroffer. tag_to_stop = current_tag; tag_to_stop.microstep++; @@ -2388,7 +2388,7 @@ void synchronize_with_other_federates() { // Advance Grant message to request for permission to execute. In the decentralized // coordination, either the after delay on the connection must be sufficiently large // enough or the STP offset must be set globally to an accurate value. - start_time = get_start_time_from_rti(get_physical_time()); + start_time = get_start_time_from_rti(lf_time(LF_PHYSICAL)); // Every federate starts out assuming that it has been granted a PTAG // at the start time, or if it has no upstream federates, a TAG. @@ -2454,7 +2454,7 @@ bool _lf_bounded_NET(tag_t* tag) { // There is a physical action upstream of some output from this // federate, and there is at least one downstream federate. // Compare the tag to the current physical time. - instant_t physical_time = get_physical_time(); + instant_t physical_time = lf_time(LF_PHYSICAL); if (physical_time + _fed.min_delay_from_physical_action_to_federate_output < tag->time) { // Can only promise up and not including this new time: tag->time = physical_time + _fed.min_delay_from_physical_action_to_federate_output - 1L; @@ -2541,7 +2541,7 @@ tag_t _lf_send_next_event_tag(tag_t tag, bool wait_for_reply) { // If time advance (TAG or PTAG) has already been granted for this tag // or a larger tag, then return immediately. - if (compare_tags(_fed.last_TAG, tag) >= 0) { + if (lf_compare_tags(_fed.last_TAG, tag) >= 0) { DEBUG_PRINT("Granted tag (%lld, %u) because TAG or PTAG has been received.", _fed.last_TAG.time - start_time, _fed.last_TAG.microstep); return _fed.last_TAG; @@ -2606,7 +2606,7 @@ tag_t _lf_send_next_event_tag(tag_t tag, bool wait_for_reply) { } // Check whether the new event on the event queue requires sending a new NET. tag_t next_tag = get_next_event_tag(); - if (compare_tags(next_tag, tag) != 0) { + if (lf_compare_tags(next_tag, tag) != 0) { _lf_send_tag(MSG_TYPE_NEXT_EVENT_TAG, next_tag, wait_for_reply); _fed.last_sent_NET = next_tag; } @@ -2635,7 +2635,7 @@ tag_t _lf_send_next_event_tag(tag_t tag, bool wait_for_reply) { // in the future. DEBUG_PRINT("Waiting for physical time to elapse or an event on the event queue."); - // The above call to _lf_bounded_NET called get_physical_time + // The above call to _lf_bounded_NET called lf_time(LF_PHYSICAL) // set _lf_last_reported_unadjusted_physical_time_ns, the // time obtained using CLOCK_REALTIME before adjustment for // clock synchronization. Since that is the clock used by diff --git a/core/federated/net_common.h b/core/federated/net_common.h index d2d3f2e1a..3cb2cc588 100644 --- a/core/federated/net_common.h +++ b/core/federated/net_common.h @@ -109,7 +109,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * is an estimate L of the one-way latency. The estimated clock error * E is therefore L - (T2 - T1). Over several cycles, the average value of E * becomes the initial offset for the - * clock at the federate. Henceforth, when get_physical_time() is + * clock at the federate. Henceforth, when lf_time(LF_PHYSICAL) is * called, the offset will be added to whatever the physical clock says. * * If clock synchronization is enabled, then the federate will also diff --git a/core/modal_models/modes.c b/core/modal_models/modes.c index 629422258..822edba1f 100644 --- a/core/modal_models/modes.c +++ b/core/modal_models/modes.c @@ -247,8 +247,8 @@ void _lf_process_mode_changes( // No further processing; drops all events upon reset (timer event was recreated by schedule and original can be removed here) } else if (state->next_mode != state->active_mode && event->trigger != NULL) { // History transition to a different mode // Remaining time that the event would have been waiting before mode was left - instant_t local_remaining_delay = event->time - (state->next_mode->deactivation_time != 0 ? state->next_mode->deactivation_time : get_start_time()); - tag_t current_logical_tag = get_current_tag(); + instant_t local_remaining_delay = event->time - (state->next_mode->deactivation_time != 0 ? state->next_mode->deactivation_time : lf_time(LF_START)); + tag_t current_logical_tag = lf_tag(); // Reschedule event with original local delay DEBUG_PRINT("Modes: Re-enqueuing event with a suspended delay of %d (previous TTH: %u, Mode suspended at: %u).", local_remaining_delay, event->time, state->next_mode->deactivation_time); @@ -298,7 +298,7 @@ void _lf_process_mode_changes( reactor_mode_state_t* state = states[i]; if (state != NULL && state->next_mode != NULL) { // Save time when mode was left to handle suspended events in the future - state->active_mode->deactivation_time = get_logical_time(); + state->active_mode->deactivation_time = lf_time(LF_LOGICAL); // Apply transition state->active_mode = state->next_mode; diff --git a/core/platform.h b/core/platform.h index 14a67c2a2..941cce803 100644 --- a/core/platform.h +++ b/core/platform.h @@ -246,4 +246,16 @@ extern int lf_clock_gettime(instant_t* t); */ extern int lf_nanosleep(instant_t requested_time); + +/** + * Macros for marking function as deprecated + */ +#ifdef __GNUC__ +#define DEPRECATED(X) X __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define DEPRECATED(X) __declspec(deprecated) X +#else +#define DEPRECATED(X) X +#endif + #endif // PLATFORM_H diff --git a/core/reactor.c b/core/reactor.c index 9c1a2c884..de8ebd6bc 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -127,7 +127,7 @@ int wait_until(instant_t logical_time_ns) { int return_value = 0; if (!fast) { LOG_PRINT("Waiting for elapsed logical time %lld.", logical_time_ns - start_time); - interval_t ns_to_wait = logical_time_ns - get_physical_time(); + interval_t ns_to_wait = logical_time_ns - lf_time(LF_PHYSICAL); if (ns_to_wait < MIN_WAIT_TIME) { DEBUG_PRINT("Wait time %lld is less than MIN_WAIT_TIME %lld. Skipping wait.", @@ -202,7 +202,7 @@ int _lf_do_step(void) { // then the reaction will be invoked and the violation reaction will not be invoked again. if (reaction->deadline > 0LL) { // Get the current physical time. - instant_t physical_time = get_physical_time(); + instant_t physical_time = lf_time(LF_PHYSICAL); // FIXME: These comments look outdated. We may need to update them. // Check for deadline violation. // There are currently two distinct deadline mechanisms: @@ -248,7 +248,7 @@ int _lf_do_step(void) { // No more reactions should be blocked at this point. //assert(pqueue_size(blocked_q) == 0); - if (compare_tags(current_tag, stop_tag) >= 0) { + if (lf_compare_tags(current_tag, stop_tag) >= 0) { return 0; } @@ -287,7 +287,7 @@ int next(void) { next_tag.time = event->time; // Deduce the microstep if (next_tag.time == current_tag.time) { - next_tag.microstep = get_microstep() + 1; + next_tag.microstep = lf_tag().microstep + 1; } else { next_tag.microstep = 0; } @@ -305,7 +305,7 @@ int next(void) { DEBUG_PRINT("***** wait_until was interrupted."); // Sleep was interrupted. // FIXME: It is unclear what would cause this to occur in this unthreaded - // runtime since schedule() is not thread safe here and should not + // runtime since lf_schedule() is not thread safe here and should not // be called asynchronously. Perhaps in some runtime such as for a // PRET machine this will be supported, so here we handle this as // if an asynchronous call to schedule has occurred. In that case, @@ -318,7 +318,7 @@ int next(void) { // Advance current time to match that of the first event on the queue. _lf_advance_logical_time(next_tag.time); - if (compare_tags(current_tag, stop_tag) >= 0) { + if (lf_compare_tags(current_tag, stop_tag) >= 0) { _lf_trigger_shutdown_reactions(); } @@ -397,7 +397,7 @@ int lf_reactor_c_main(int argc, char* argv[]) { // If the stop_tag is (0,0), also insert the shutdown // reactions. This can only happen if the timeout time // was set to 0. - if (compare_tags(current_tag, stop_tag) >= 0) { + if (lf_compare_tags(current_tag, stop_tag) >= 0) { _lf_trigger_shutdown_reactions(); // _lf_trigger_shutdown_reactions(); } DEBUG_PRINT("Running the program's main loop."); diff --git a/core/reactor.h b/core/reactor.h index 13c6267fc..4342f6af5 100644 --- a/core/reactor.h +++ b/core/reactor.h @@ -103,8 +103,24 @@ void _lf_set_present(bool* is_present_field); */ #define _LF_SET(out, val) \ do { \ + /* We need to assign "val" to "out->value" since we need to give "val" an address */ \ + /* even if it is a literal */ \ out->value = val; \ _lf_set_present(&out->is_present); \ + if (out->token != NULL) { \ + /* The cast "*((void**) &out->value)" is a hack to make the code */ \ + /* compile with non-token types where val is not a pointer. */ \ + lf_token_t* token = _lf_initialize_token_with_value(out->token, *((void**) &out->value), 1); \ + token->ref_count = out->num_destinations; \ + out->token = token; \ + out->token->ok_to_free = token_and_value; \ + if (out->destructor != NULL) { \ + out->token->destructor = out->destructor; \ + } \ + if (out->copy_constructor != NULL) { \ + out->token->copy_constructor = out->copy_constructor; \ + } \ + } \ } while(0) /** @@ -121,7 +137,7 @@ do { \ * @see lf_token_t */ #ifndef __cplusplus -#define _LF_SET_ARRAY(out, val, element_size, length) \ +#define _LF_SET_ARRAY(out, val, length) \ do { \ _lf_set_present(&out->is_present); \ lf_token_t* token = _lf_initialize_token_with_value(out->token, val, length); \ @@ -130,7 +146,7 @@ do { \ out->value = token->value; \ } while(0) #else -#define _LF_SET_ARRAY(out, val, element_size, length) \ +#define _LF_SET_ARRAY(out, val, length) \ do { \ _lf_set_present(&out->is_present); \ lf_token_t* token = _lf_initialize_token_with_value(out->token, val, length); \ @@ -247,6 +263,35 @@ do { \ } while(0) #endif +/** + * Set the destructor used to free "token->value" set on "out". + * That memory will be automatically freed once all downstream + * reactions no longer need the value. + * + * @param out The output port (by name) or input of a contained + * reactor in form input_name.port_name. + * @param dtor A pointer to a void function that takes a pointer argument + * or NULL to use the default void free(void*) function. + */ +#define _LF_SET_DESTRUCTOR(out, dtor) \ +do { \ + out->destructor = dtor; \ +} while(0) + +/** + * Set the destructor used to copy construct "token->value" received + * by "in" if "in" is mutable. + * + * @param out The output port (by name) or input of a contained + * reactor in form input_name.port_name. + * @param cpy_ctor A pointer to a void* function that takes a pointer argument + * or NULL to use the memcpy operator. + */ +#define _LF_SET_COPY_CONSTRUCTOR(out, cpy_ctor) \ +do { \ + out->copy_constructor = cpy_ctor; \ +} while(0) + /** * Macro for extracting the deadline from the index of a reaction. * The reaction queue is sorted according to this index, and the @@ -360,7 +405,7 @@ typedef enum {inactive = 0, queued, running} reaction_status_t; /** * Handles for scheduled triggers. These handles are returned - * by schedule() functions. The intent is that the handle can be + * by lf_schedule() functions. The intent is that the handle can be * used to cancel a future scheduled event, but this is not * implemented yet. */ @@ -426,6 +471,10 @@ typedef struct lf_token_t { size_t length; /** The number of input ports that have not already reacted to the message. */ int ref_count; + /** The destructor or NULL to use the default free(). */ + void (*destructor) (void* value); + /** The copy constructor or NULL to use memcpy. */ + void* (*copy_constructor) (void* value); /** * Indicator of whether this token is expected to be freed. * Tokens that are created at the start of execution and associated with output @@ -697,7 +746,7 @@ void _lf_initialize_trigger_objects(void); void _lf_pop_events(void); /** - * Internal version of the schedule() function, used by generated + * Internal version of the lf_schedule() function, used by generated * _lf_start_timers() function. * @param trigger The action or timer to be triggered. * @param delay Offset of the event release. diff --git a/core/reactor_common.c b/core/reactor_common.c index 30ee0984f..cada902d8 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -272,7 +272,7 @@ void _lf_free_all_reactors(void) { * calling this function. */ void _lf_set_stop_tag(tag_t tag) { - if (compare_tags(tag, stop_tag) < 0) { + if (lf_compare_tags(tag, stop_tag) < 0) { stop_tag = tag; } } @@ -351,6 +351,57 @@ typedef enum token_freed { TOKEN_FREED // The value and the token were freed. } token_freed; + +/** + * Determine which part of the token should be freed and + * free each part correspondingly. + * + * @param token Pointer to a token. + * @return NOT_FREED if nothing was freed, VALUE_FREED if the value + * was freed, and TOKEN_FREED if both the value and the token were + * freed. + */ +token_freed _lf_free_token(lf_token_t* token) { + if (token == NULL) { + return NOT_FREED; + } + token_freed result = NOT_FREED; + if (token->value != NULL) { + // Count frees to issue a warning if this is never freed. + // Do not free the value field if it is garbage collected and token's ok_to_free field is not "token_and_value". + _lf_count_payload_allocations--; + if (OK_TO_FREE != token_only && token->ok_to_free == token_and_value) { + DEBUG_PRINT("_lf_free_token: Freeing allocated memory for payload (token value): %p", token->value); + if (token->destructor == NULL) { + free(token->value); + } else { + token->destructor(token->value); + } + } + token->value = NULL; + result = VALUE_FREED; + } + // Tokens that are created at the start of execution and associated with + // output ports or actions are pointed to by those actions and output + // ports and should not be freed. They are expected to be reused instead. + if (token->ok_to_free) { + // Need to free the lf_token_t struct also. + if (_lf_token_recycling_bin_size < _LF_TOKEN_RECYCLING_BIN_SIZE_LIMIT) { + // Recycle instead of freeing. + token->next_free = _lf_token_recycling_bin; + _lf_token_recycling_bin = token; + _lf_token_recycling_bin_size++; + } else { + // Recycling bin is full. + free(token); + } + _lf_count_token_allocations--; + DEBUG_PRINT("_lf_free_token: Freeing allocated memory for token: %p", token); + result = TOKEN_FREED; + } + return result; +} + /** * Decrement the reference count of the specified token. * If the reference count hits 0, free the memory for the value @@ -362,46 +413,16 @@ typedef enum token_freed { * freed. */ token_freed _lf_done_using(lf_token_t* token) { - token_freed result = NOT_FREED; - if (token == NULL) return result; + if (token == NULL) { + return NOT_FREED; + } if (token->ref_count == 0) { warning_print("Token being freed that has already been freed: %p", token); return NOT_FREED; } token->ref_count--; DEBUG_PRINT("_lf_done_using: ref_count = %d.", token->ref_count); - if (token->ref_count == 0) { - if (token->value != NULL) { - // Count frees to issue a warning if this is never freed. - // Do not free the value field if it is garbage collected and token's ok_to_free field is not "token_and_value". - _lf_count_payload_allocations--; - if(OK_TO_FREE != token_only && token->ok_to_free == token_and_value) { - DEBUG_PRINT("_lf_done_using: Freeing allocated memory for payload (token value): %p", token->value); - free(token->value); - } - token->value = NULL; - result = VALUE_FREED; - } - // Tokens that are created at the start of execution and associated with - // output ports or actions are pointed to by those actions and output - // ports and should not be freed. They are expected to be reused instead. - if (token->ok_to_free) { - // Need to free the lf_token_t struct also. - if (_lf_token_recycling_bin_size < _LF_TOKEN_RECYCLING_BIN_SIZE_LIMIT) { - // Recycle instead of freeing. - token->next_free = _lf_token_recycling_bin; - _lf_token_recycling_bin = token; - _lf_token_recycling_bin_size++; - } else { - // Recycling bin is full. - free(token); - } - _lf_count_token_allocations--; - DEBUG_PRINT("_lf_done_using: Freeing allocated memory for token: %p", token); - result = TOKEN_FREED; - } - } - return result; + return token->ref_count == 0 ? _lf_free_token(token) : NOT_FREED; } /** @@ -488,6 +509,8 @@ lf_token_t* _lf_create_token(size_t element_size) { token->length = 0; token->element_size = element_size; token->ref_count = 0; + token->destructor = NULL; + token->copy_constructor = NULL; token->ok_to_free = no; token->next_free = NULL; return token; @@ -571,7 +594,7 @@ lf_token_t* _lf_initialize_token(lf_token_t* token, size_t length) { * @param tag The tag to check against stop tag */ bool _lf_is_tag_after_stop_tag(tag_t tag) { - return (compare_tags(tag, stop_tag) > 0); + return (lf_compare_tags(tag, stop_tag) > 0); } /** @@ -626,7 +649,7 @@ void _lf_pop_events() { // the reaction can access the value. event->trigger->intended_tag = event->intended_tag; // And check if it is in the past compared to the current tag. - if (compare_tags(event->intended_tag, + if (lf_compare_tags(event->intended_tag, current_tag) < 0) { // Mark the triggered reaction with a STP violation reaction->is_STP_violated = true; @@ -727,7 +750,7 @@ void _lf_initialize_timer(trigger_t* timer) { // && (timer->offset != 0 || timer->period != 0)) { event_t* e = _lf_get_new_event(); e->trigger = timer; - e->time = get_logical_time() + timer->offset; + e->time = lf_time(LF_LOGICAL) + timer->offset; _lf_add_suspended_event(e); return; } @@ -752,7 +775,7 @@ void _lf_initialize_timer(trigger_t* timer) { // Recycle event_t structs, if possible. event_t* e = _lf_get_new_event(); e->trigger = timer; - e->time = get_logical_time() + delay; + e->time = lf_time(LF_LOGICAL) + delay; // NOTE: No lock is being held. Assuming this only happens at startup. pqueue_insert(event_q, e); tracepoint_schedule(timer, delay); // Trace even though schedule is not called. @@ -864,12 +887,12 @@ void _lf_replace_token(event_t* event, lf_token_t* token) { */ int _lf_schedule_at_tag(trigger_t* trigger, tag_t tag, lf_token_t* token) { - tag_t current_logical_tag = get_current_tag(); + tag_t current_logical_tag = lf_tag(); DEBUG_PRINT("_lf_schedule_at_tag() called with tag (%lld, %u) at tag (%lld, %u).", tag.time - start_time, tag.microstep, current_logical_tag.time - start_time, current_logical_tag.microstep); - if (compare_tags(tag, current_logical_tag) <= 0) { + if (lf_compare_tags(tag, current_logical_tag) <= 0) { warning_print("_lf_schedule_at_tag(): requested to schedule an event in the past."); return -1; } @@ -1070,7 +1093,7 @@ trigger_handle_t _lf_schedule(trigger_t* trigger, interval_t extra_delay, lf_tok // If schedule is called after stop_tag // This is a critical condition. _lf_done_using(token); - warning_print("schedule() called after stop tag."); + warning_print("lf_schedule() called after stop tag."); return 0; } @@ -1126,7 +1149,7 @@ trigger_handle_t _lf_schedule(trigger_t* trigger, interval_t extra_delay, lf_tok // modify the intended time. if (trigger->is_physical) { // Get the current physical time and assign it as the intended time. - intended_time = get_physical_time() + delay; + intended_time = lf_time(LF_PHYSICAL) + delay; } else { // FIXME: We need to verify that we are executing within a reaction? // See reactor_threaded. @@ -1229,7 +1252,7 @@ trigger_handle_t _lf_schedule(trigger_t* trigger, interval_t extra_delay, lf_tok default: if (existing->time == current_tag.time && pqueue_find_equal_same_priority(event_q, existing) != NULL) { - if (_lf_is_tag_after_stop_tag((tag_t){.time=existing->time,.microstep=get_microstep()+1})) { + if (_lf_is_tag_after_stop_tag((tag_t){.time=existing->time,.microstep=lf_tag().microstep+1})) { // Scheduling e will incur a microstep at timeout, // which is illegal. _lf_recycle_event(e); @@ -1342,7 +1365,7 @@ trigger_handle_t _lf_insert_reactions_for_trigger(trigger_t* trigger, lf_token_t // Check if the trigger has violated the STP offset bool is_STP_violated = false; #ifdef FEDERATED - if (compare_tags(trigger->intended_tag, get_current_tag()) < 0) { + if (lf_compare_tags(trigger->intended_tag, lf_tag()) < 0) { is_STP_violated = true; } #ifdef FEDERATED_CENTRALIZED @@ -1393,7 +1416,7 @@ trigger_handle_t _lf_insert_reactions_for_trigger(trigger_t* trigger, lf_token_t if (reaction->status == inactive) { reaction->is_STP_violated = is_STP_violated; _lf_trigger_reaction(reaction, -1); - LOG_PRINT("Enqueued reaction %s at time %lld.", reaction->name, get_logical_time()); + LOG_PRINT("Enqueued reaction %s at time %lld.", reaction->name, lf_time(LF_LOGICAL)); } } @@ -1509,7 +1532,7 @@ lf_token_t* _lf_set_new_array_impl(lf_token_t* token, size_t length, int num_des */ bool _lf_check_deadline(self_base_t* self, bool invoke_deadline_handler) { reaction_t* reaction = self->executing_reaction; - if (get_physical_time() > get_logical_time() + reaction->deadline) { + if (lf_time(LF_PHYSICAL) > lf_time(LF_LOGICAL) + reaction->deadline) { if (invoke_deadline_handler) { reaction->deadline_violation_handler(self); } @@ -1646,7 +1669,7 @@ void schedule_output_reactions(reaction_t* reaction, int worker) { #endif if (downstream_to_execute_now->deadline > 0LL) { // Get the current physical time. - instant_t physical_time = get_physical_time(); + instant_t physical_time = lf_time(LF_PHYSICAL); // Check for deadline violation. if (physical_time > current_tag.time + downstream_to_execute_now->deadline) { // Deadline violation has occurred. @@ -1697,23 +1720,34 @@ lf_token_t* writable_copy(lf_token_t* token) { if (token->ref_count == 1) { DEBUG_PRINT("writable_copy: Avoided copy because reference count is %d.", token->ref_count); return token; - } else { - DEBUG_PRINT("writable_copy: Copying array because reference count is greater than 1. It is %d.", token->ref_count); + } + DEBUG_PRINT("writable_copy: Copying array because reference count is greater than 1. It is %d.", token->ref_count); + void* copy; + if (token->copy_constructor == NULL) { + DEBUG_PRINT("writable_copy: Copy constructor is NULL. Using default strategy."); size_t size = token->element_size * token->length; if (size == 0) { return token; } - void* copy = malloc(size); + copy = malloc(size); DEBUG_PRINT("Allocating memory for writable copy %p.", copy); memcpy(copy, token->value, size); // Count allocations to issue a warning if this is never freed. - _lf_count_payload_allocations++; - // Create a new, dynamically allocated token. - lf_token_t* result = create_token(token->element_size); - result->length = token->length; - result->value = copy; - return result; + } else { + DEBUG_PRINT("writable_copy: Copy constructor is not NULL. Using copy constructor."); + if (token->destructor == NULL) { + warning_print("writable_copy: Using non-default copy constructor without setting destructor. Potential memory leak."); + } + copy = token->copy_constructor(token->value); } + // Create a new, dynamically allocated token. + lf_token_t* result = create_token(token->element_size); + _lf_count_payload_allocations++; + result->length = token->length; + result->value = copy; + result->destructor = token->destructor; + result->copy_constructor = token->copy_constructor; + return result; } /** @@ -1913,7 +1947,7 @@ void initialize(void) { // Initialize the trigger table. _lf_initialize_trigger_objects(); - physical_start_time = get_physical_time(); + physical_start_time = lf_time(LF_PHYSICAL); current_tag.time = physical_start_time; start_time = current_tag.time; @@ -1968,7 +2002,7 @@ void termination(void) { } // Print elapsed times. // If these are negative, then the program failed to start up. - interval_t elapsed_time = get_elapsed_logical_time(); + interval_t elapsed_time = lf_time(LF_ELAPSED_LOGICAL); if (elapsed_time >= 0LL) { char time_buffer[29]; // 28 bytes is enough for the largest 64 bit number: 9,223,372,036,854,775,807 lf_comma_separated_time(time_buffer, elapsed_time); @@ -1977,7 +2011,7 @@ void termination(void) { // If physical_start_time is 0, then execution didn't get far enough along // to initialize this. if (physical_start_time > 0LL) { - lf_comma_separated_time(time_buffer, get_elapsed_physical_time()); + lf_comma_separated_time(time_buffer, lf_time(LF_ELAPSED_PHYSICAL)); printf("---- Elapsed physical time (in nsec): %s\n", time_buffer); } } diff --git a/core/tag.c b/core/tag.c index 5269c926c..6dba3d4fc 100644 --- a/core/tag.c +++ b/core/tag.c @@ -2,6 +2,7 @@ * @file * @author Edward A. Lee * @author Soroush Bateni + * @author Hou Seng (Steven) Wong * * @section LICENSE Copyright (c) 2020, The University of California at Berkeley. @@ -83,7 +84,7 @@ interval_t _lf_global_test_physical_clock_offset = 0LL; * @param tag2 * @return -1, 0, or 1 depending on the relation. */ -int compare_tags(tag_t tag1, tag_t tag2) { +int lf_compare_tags(tag_t tag1, tag_t tag2) { if (tag1.time < tag2.time) { return -1; } else if (tag1.time > tag2.time) { @@ -97,6 +98,13 @@ int compare_tags(tag_t tag1, tag_t tag2) { } } +/** + * @deprecated version of 'lf_compare_tags' + */ +int compare_tags(tag_t tag1, tag_t tag2) { + return lf_compare_tags(tag1, tag2); +} + /** * Delay a tag by the specified time interval to realize the "after" keyword. * If either the time interval or the time field of the tag is NEVER, @@ -113,54 +121,59 @@ int compare_tags(tag_t tag1, tag_t tag2) { * @param tag The tag to increment. * @param interval The time interval. */ -tag_t delay_tag(tag_t tag, interval_t interval) { - if (tag.time == NEVER || interval == NEVER) return tag; - tag_t result = tag; - if (interval == 0LL) { - // Note that unsigned variables will wrap on overflow. - // This is probably the only reasonable thing to do with overflowing - // microsteps. - result.microstep++; - } else { - // Note that overflow in C is undefined for signed variables. - if (FOREVER - interval < result.time) { - result.time = FOREVER; - } else { - result.time += interval; - } - result.microstep = 0; - } - return result; +tag_t _lf_delay_tag(tag_t tag, interval_t interval) { + if (tag.time == NEVER || interval == NEVER) return tag; + tag_t result = tag; + if (interval == 0LL) { + // Note that unsigned variables will wrap on overflow. + // This is probably the only reasonable thing to do with overflowing + // microsteps. + result.microstep++; + } else { + // Note that overflow in C is undefined for signed variables. + if (FOREVER - interval < result.time) { + result.time = FOREVER; + } else { + result.time += interval; + } + result.microstep = 0; + } + return result; } /** * Return the elapsed logical time in nanoseconds since the start of execution. + * @deprecated */ interval_t get_elapsed_logical_time() { - return current_tag.time - start_time; + return lf_time(LF_ELAPSED_LOGICAL); } /** * Return the current tag, a logical time, microstep pair. + * @deprecated */ tag_t get_current_tag() { - return current_tag; + return lf_tag(); } /** * Return the current logical time in nanoseconds since January 1, 1970. + * @deprecated */ instant_t get_logical_time() { - return current_tag.time; + return lf_time(LF_LOGICAL); } /** * Return the current microstep. + * @deprecated */ microstep_t get_microstep() { - return current_tag.microstep; + return lf_tag().microstep; } + /** * Stores the last reported absolute snapshot of the * physical clock. @@ -182,7 +195,7 @@ instant_t _lf_last_reported_unadjusted_physical_time_ns = NEVER; * Return the current physical time in nanoseconds since January 1, 1970, * adjusted by the global physical time offset. */ -instant_t get_physical_time() { +instant_t _lf_physical_time() { // Get the current clock value int result = lf_clock_gettime(&_lf_last_reported_unadjusted_physical_time_ns); @@ -220,25 +233,33 @@ instant_t get_physical_time() { return _lf_last_reported_physical_time_ns; } +/** + * @deprecated version of '_lf_physical_time' + */ +instant_t get_physical_time() { + return lf_time(LF_PHYSICAL); +} + /** * Return the physical time of the start of execution in nanoseconds. * * On many platforms, this is the number of nanoseconds * since January 1, 1970, but it is actually platform dependent. * * @return A time instant. + * @deprecated */ instant_t get_start_time() { - return start_time; + return lf_time(LF_START); } - /** * Return the elapsed physical time in nanoseconds. * This is the time returned by get_physical_time() minus the * physical start time as measured by get_physical_time() when * the program was started. + * @deprecated */ instant_t get_elapsed_physical_time() { - return get_physical_time() - physical_start_time; + return lf_time(LF_ELAPSED_PHYSICAL); } /** @@ -247,10 +268,17 @@ instant_t get_elapsed_physical_time() { * and get_elpased_physical_time() will have this specified offset * added to what it would have returned before the call. */ -void set_physical_clock_offset(interval_t offset) { +void lf_set_physical_clock_offset(interval_t offset) { _lf_global_test_physical_clock_offset += offset; } +/** + * @deprecated version of 'lf_set_physical_clock_offset' + */ +void set_physical_clock_offset(interval_t offset) { + lf_set_physical_clock_offset(offset); +} + /** * Store into the specified buffer a string giving a human-readable * rendition of the specified time. The buffer must have length at least @@ -266,85 +294,85 @@ void set_physical_clock_offset(interval_t offset) { * @return The number of characters written (not counting the null terminator). */ size_t lf_readable_time(char* buffer, instant_t time) { - char* original_buffer = buffer; - bool lead = false; // Set to true when first clause has been printed. - if (time > WEEKS(1)) { - lead = true; - size_t printed = lf_comma_separated_time(buffer, time / WEEKS(1)); - time = time % WEEKS(1); - buffer += printed; - sprintf(buffer, " weeks"); - buffer += 6; - } - if (time > DAYS(1)) { - if (lead == true) { - sprintf(buffer, ", "); - buffer += 2; - } - lead = true; - size_t printed = lf_comma_separated_time(buffer, time / DAYS(1)); - time = time % DAYS(1); - buffer += printed; - sprintf(buffer, " days"); - buffer += 5; - } - if (time > HOURS(1)) { - if (lead == true) { - sprintf(buffer, ", "); - buffer += 2; - } - lead = true; - size_t printed = lf_comma_separated_time(buffer, time / HOURS(1)); - time = time % HOURS(1); - buffer += printed; - sprintf(buffer, " hours"); - buffer += 6; - } - if (time > MINUTES(1)) { - if (lead == true) { - sprintf(buffer, ", "); - buffer += 2; - } - lead = true; - size_t printed = lf_comma_separated_time(buffer, time / MINUTES(1)); - time = time % MINUTES(1); - buffer += printed; - sprintf(buffer, " minutes"); - buffer += 8; - } - if (time > SECONDS(1)) { - if (lead == true) { - sprintf(buffer, ", "); - buffer += 2; - } - lead = true; - size_t printed = lf_comma_separated_time(buffer, time / SECONDS(1)); - time = time % SECONDS(1); - buffer += printed; - sprintf(buffer, " seconds"); - buffer += 8; - } - if (time > (instant_t)0) { - if (lead == true) { - sprintf(buffer, ", "); - buffer += 2; - } - const char* units = "nanoseconds"; - if (time % MSEC(1) == (instant_t) 0) { - units = "milliseconds"; - time = time % MSEC(1); - } else if (time % USEC(1) == (instant_t) 0) { - units = "microseconds"; - time = time % USEC(1); - } - size_t printed = lf_comma_separated_time(buffer, time); - buffer += printed; - sprintf(buffer, " %s", units); - buffer += strlen(units) + 1; - } else { - sprintf(buffer, "0"); - } - return (buffer - original_buffer); + char* original_buffer = buffer; + bool lead = false; // Set to true when first clause has been printed. + if (time > WEEKS(1)) { + lead = true; + size_t printed = lf_comma_separated_time(buffer, time / WEEKS(1)); + time = time % WEEKS(1); + buffer += printed; + sprintf(buffer, " weeks"); + buffer += 6; + } + if (time > DAYS(1)) { + if (lead == true) { + sprintf(buffer, ", "); + buffer += 2; + } + lead = true; + size_t printed = lf_comma_separated_time(buffer, time / DAYS(1)); + time = time % DAYS(1); + buffer += printed; + sprintf(buffer, " days"); + buffer += 5; + } + if (time > HOURS(1)) { + if (lead == true) { + sprintf(buffer, ", "); + buffer += 2; + } + lead = true; + size_t printed = lf_comma_separated_time(buffer, time / HOURS(1)); + time = time % HOURS(1); + buffer += printed; + sprintf(buffer, " hours"); + buffer += 6; + } + if (time > MINUTES(1)) { + if (lead == true) { + sprintf(buffer, ", "); + buffer += 2; + } + lead = true; + size_t printed = lf_comma_separated_time(buffer, time / MINUTES(1)); + time = time % MINUTES(1); + buffer += printed; + sprintf(buffer, " minutes"); + buffer += 8; + } + if (time > SECONDS(1)) { + if (lead == true) { + sprintf(buffer, ", "); + buffer += 2; + } + lead = true; + size_t printed = lf_comma_separated_time(buffer, time / SECONDS(1)); + time = time % SECONDS(1); + buffer += printed; + sprintf(buffer, " seconds"); + buffer += 8; + } + if (time > (instant_t)0) { + if (lead == true) { + sprintf(buffer, ", "); + buffer += 2; + } + const char* units = "nanoseconds"; + if (time % MSEC(1) == (instant_t) 0) { + units = "milliseconds"; + time = time % MSEC(1); + } else if (time % USEC(1) == (instant_t) 0) { + units = "microseconds"; + time = time % USEC(1); + } + size_t printed = lf_comma_separated_time(buffer, time); + buffer += printed; + sprintf(buffer, " %s", units); + buffer += strlen(units) + 1; + } else { + sprintf(buffer, "0"); + } + return (buffer - original_buffer); } /** @@ -358,7 +386,7 @@ size_t lf_readable_time(char* buffer, instant_t time) { * the null terminator). */ size_t lf_comma_separated_time(char* buffer, instant_t time) { - size_t result = 0; // The number of characters printed. + size_t result = 0; // The number of characters printed. // If the number is zero, print it and return. if (time == (instant_t)0) { sprintf(buffer, "0"); @@ -366,9 +394,9 @@ size_t lf_comma_separated_time(char* buffer, instant_t time) { } // If the number is negative, print a minus sign. if (time < (instant_t)0) { - sprintf(buffer, "-"); - buffer++; - result++; + sprintf(buffer, "-"); + buffer++; + result++; } int count = 0; // Assume the time value is no larger than 64 bits. @@ -404,7 +432,7 @@ size_t lf_comma_separated_time(char* buffer, instant_t time) { * variant. */ #ifdef __cplusplus -tag_t convert_volatile_tag_to_nonvolatile(tag_t volatile const& vtag) { +tag_t _lf_convert_volatile_tag_to_nonvolatile(tag_t volatile const& vtag) { tag_t non_volatile_tag; non_volatile_tag.time = vtag.time; non_volatile_tag.microstep = vtag.microstep; @@ -415,7 +443,50 @@ tag_t convert_volatile_tag_to_nonvolatile(tag_t volatile const& vtag) { * @note This is an undefined behavior in C and should * be used with utmost caution. See Section 6.7.2 of the C99 standard. */ -tag_t convert_volatile_tag_to_nonvolatile(tag_t volatile vtag) { +tag_t _lf_convert_volatile_tag_to_nonvolatile(tag_t volatile vtag) { return vtag; } #endif + +/** + * Return the current tag, a logical time, microstep pair. + */ +tag_t lf_tag() { + return current_tag; +} + + +/** + * Get the time specified by "type". + * + * Example use cases: + * - Getting the starting time: + * lf_time(LF_START) + * + * - Getting the elapsed physical time: + * lf_time(LF_ELAPSED_PHYSICAL) + * + * - Getting the logical time + * lf_time(LF_LOGICAL) + * + * @param type A field in an enum specifying the time type. + * See enum "lf_time_type" above. + * @return The desired time + */ +instant_t lf_time(lf_time_type type) { + switch (type) + { + case LF_LOGICAL: + return current_tag.time; + case LF_PHYSICAL: + return _lf_physical_time(); + case LF_ELAPSED_LOGICAL: + return current_tag.time - start_time; + case LF_ELAPSED_PHYSICAL: + return _lf_physical_time() - physical_start_time; + case LF_START: + return start_time; + default: + return NEVER; + } +} \ No newline at end of file diff --git a/core/tag.h b/core/tag.h index 62a1039ba..c607ed67c 100644 --- a/core/tag.h +++ b/core/tag.h @@ -2,6 +2,7 @@ * @file * @author Edward A. Lee * @author Soroush Bateni + * @author Hou Seng (Steven) Wong * * @section LICENSE Copyright (c) 2020, The University of California at Berkeley. @@ -94,32 +95,50 @@ typedef tag_t tag_interval_t; * @param tag2 * @return -1, 0, or 1 depending on the relation. */ -int compare_tags(tag_t tag1, tag_t tag2); +int lf_compare_tags(tag_t tag1, tag_t tag2); +DEPRECATED(int compare_tags(tag_t tag1, tag_t tag2)); /** - * Delay a tag by the specified time interval to realize the "after" keyword. - * If either the time interval or the time field of the tag is NEVER, - * return the unmodified tag. - * If the time interval is 0LL, add one to the microstep, leave - * the time field alone, and return the result. - * Otherwise, add the interval to the time field of the tag and reset - * the microstep to 0. - * If the sum overflows, saturate the time value at FOREVER. - * - * Note that normally it makes no sense to call this with a negative - * interval (except NEVER), but this is not checked. - * - * @param tag The tag to increment. - * @param interval The time interval. + * An enum for specifying the desired tag when calling "lf_time" + */ +typedef enum _lf_time_type { + LF_LOGICAL, + LF_PHYSICAL, + LF_ELAPSED_LOGICAL, + LF_ELAPSED_PHYSICAL, + LF_START +} lf_time_type; + +/** + * Return the current tag, a logical time, microstep pair. + */ +tag_t lf_tag(); + +/** + * Get the time specified by "type". + * + * Example use cases: + * - Getting the starting time: + * lf_time(LF_START) + * + * - Getting the elapsed physical time: + * lf_time(LF_ELAPSED_PHYSICAL) + * + * - Getting the logical time + * lf_time(LF_LOGICAL) + * + * @param type A field in an enum specifying the tag type. + * See enum "lf_tag_type" above. + * @return The desired time */ -tag_t delay_tag(tag_t tag, interval_t interval); +instant_t lf_time(lf_time_type type); /** * Return the elapsed logical time in nanoseconds * since the start of execution. * @return A time interval. */ -interval_t get_elapsed_logical_time(void); +DEPRECATED(interval_t get_elapsed_logical_time(void)); /** * Store into the specified buffer a string giving a human-readable @@ -155,17 +174,17 @@ size_t lf_comma_separated_time(char* buffer, instant_t time); * * @return A time instant. */ -instant_t get_logical_time(void); +DEPRECATED(instant_t get_logical_time(void)); /** * Return the current tag, a logical time, microstep pair. */ -tag_t get_current_tag(void); +DEPRECATED(tag_t get_current_tag(void)); /** * Return the current microstep. */ -microstep_t get_microstep(void); +DEPRECATED(microstep_t get_microstep(void)); /** * Global physical clock offset. @@ -199,7 +218,7 @@ extern interval_t _lf_epoch_offset; * since January 1, 1970, but it is actually platform dependent. * @return A time instant. */ -instant_t get_physical_time(void); +DEPRECATED(instant_t get_physical_time(void)); /** * Return the elapsed physical time in nanoseconds. @@ -207,7 +226,7 @@ instant_t get_physical_time(void); * physical start time as measured by get_physical_time(void) when * the program was started. */ -instant_t get_elapsed_physical_time(void); +DEPRECATED(instant_t get_elapsed_physical_time(void)); /** * Set a fixed offset to the physical clock. @@ -215,7 +234,8 @@ instant_t get_elapsed_physical_time(void); * and get_elpased_physical_time(void) will have this specified offset * added to what it would have returned before the call. */ -void set_physical_clock_offset(interval_t offset); +void lf_set_physical_clock_offset(interval_t offset); +DEPRECATED(void set_physical_clock_offset(interval_t offset)); /** * Return the physical and logical time of the start of execution in nanoseconds. @@ -223,20 +243,38 @@ void set_physical_clock_offset(interval_t offset); * since January 1, 1970, but it is actually platform dependent. * @return A time instant. */ -instant_t get_start_time(void); +DEPRECATED(instant_t get_start_time(void)); + +/** + * Delay a tag by the specified time interval to realize the "after" keyword. + * If either the time interval or the time field of the tag is NEVER, + * return the unmodified tag. + * If the time interval is 0LL, add one to the microstep, leave + * the time field alone, and return the result. + * Otherwise, add the interval to the time field of the tag and reset + * the microstep to 0. + * If the sum overflows, saturate the time value at FOREVER. + * + * Note that normally it makes no sense to call this with a negative + * interval (except NEVER), but this is not checked. + * + * @param tag The tag to increment. + * @param interval The time interval. + */ +tag_t _lf_delay_tag(tag_t tag, interval_t interval); /** * For C++ compatibility, take a volatile tag_t and return a non-volatile * variant. */ #ifdef __cplusplus -tag_t convert_volatile_tag_to_nonvolatile(const volatile tag_t &vtag); +tag_t _lf_convert_volatile_tag_to_nonvolatile(tag_t volatile const& vtag); #else /** * @note This is an undefined behavior in C and should * be used with utmost caution. See Section 6.7.2 of the C99 standard. */ -tag_t convert_volatile_tag_to_nonvolatile(tag_t volatile vtag); +tag_t _lf_convert_volatile_tag_to_nonvolatile(tag_t volatile vtag); #endif #endif // TAG_H diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index a9560c570..0a1d8604e 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -142,12 +142,12 @@ void _lf_increment_global_tag_barrier_already_locked(tag_t future_tag) { warning_print("Attempting to raise a barrier after the stop tag."); future_tag = stop_tag; } - tag_t current_tag = get_current_tag(); + tag_t current_tag = lf_tag(); // Check to see if future_tag is actually in the future. - if (compare_tags(future_tag, current_tag) > 0) { + if (lf_compare_tags(future_tag, current_tag) > 0) { // Future tag is actually in the future. // See whether it is smaller than any pre-existing barrier. - if (compare_tags(future_tag, _lf_global_tag_advancement_barrier.horizon) < 0) { + if (lf_compare_tags(future_tag, _lf_global_tag_advancement_barrier.horizon) < 0) { // The future tag is smaller than the current horizon of the barrier. // Therefore, we should prevent logical time from reaching the // future tag. @@ -279,7 +279,7 @@ int _lf_wait_on_global_tag_barrier(tag_t proposed_tag) { // Wait until the global barrier semaphore on logical time is zero // and the proposed_time is larger than or equal to the horizon. while (_lf_global_tag_advancement_barrier.requestors > 0 - && compare_tags(proposed_tag, _lf_global_tag_advancement_barrier.horizon) >= 0 + && lf_compare_tags(proposed_tag, _lf_global_tag_advancement_barrier.horizon) >= 0 ) { result = 1; LOG_PRINT("Waiting on barrier for tag (%lld, %u).", proposed_tag.time - start_time, proposed_tag.microstep); @@ -425,7 +425,7 @@ bool wait_until(instant_t logical_time_ns, lf_cond_t* condition) { #endif if (!fast) { // Get physical time as adjusted by clock synchronization offset. - instant_t current_physical_time = get_physical_time(); + instant_t current_physical_time = lf_time(LF_PHYSICAL); // We want to wait until that adjusted time matches the logical time. interval_t ns_to_wait = wait_until_time_ns - current_physical_time; // We should not wait if that adjusted time is already ahead @@ -462,10 +462,10 @@ bool wait_until(instant_t logical_time_ns, lf_cond_t* condition) { DEBUG_PRINT("-------- wait_until interrupted before timeout."); // Wait did not time out, which means that there - // may have been an asynchronous call to schedule(). + // may have been an asynchronous call to lf_schedule(). // Continue waiting. // Do not adjust current_tag.time here. If there was an asynchronous - // call to schedule(), it will have put an event on the event queue, + // call to lf_schedule(), it will have put an event on the event queue, // and current_tag.time will be set to that time when that event is pulled. return_value = false; } else { @@ -474,7 +474,7 @@ bool wait_until(instant_t logical_time_ns, lf_cond_t* condition) { // Unfortunately, at least on Macs, pthread_cond_timedwait appears // to be implemented incorrectly and it returns well short of the target // time. Check for this condition and wait again if necessary. - interval_t ns_to_wait = wait_until_time_ns - get_physical_time(); + interval_t ns_to_wait = wait_until_time_ns - lf_time(LF_PHYSICAL); // We should not wait if that adjusted time is already ahead // of logical time. if (ns_to_wait < MIN_WAIT_TIME) { @@ -485,7 +485,7 @@ bool wait_until(instant_t logical_time_ns, lf_cond_t* condition) { return wait_until(wait_until_time_ns, condition); } - DEBUG_PRINT("-------- Returned from wait, having waited %lld ns.", get_physical_time() - current_physical_time); + DEBUG_PRINT("-------- Returned from wait, having waited %lld ns.", lf_time(LF_PHYSICAL) - current_physical_time); } return return_value; } @@ -512,7 +512,7 @@ tag_t get_next_event_tag() { if (next_tag.time == current_tag.time) { DEBUG_PRINT("Earliest event matches current time. Incrementing microstep. Event is dummy: %d.", event->is_dummy); - next_tag.microstep = get_microstep() + 1; + next_tag.microstep = lf_tag().microstep + 1; } else { next_tag.microstep = 0; } @@ -590,7 +590,7 @@ void _lf_next_locked() { // federates. If an action triggers during that wait, it will unblock // and return with a time (typically) less than the next_time. tag_t grant_tag = send_next_event_tag(next_tag, true); // true means this blocks. - if (compare_tags(grant_tag, next_tag) < 0) { + if (lf_compare_tags(grant_tag, next_tag) < 0) { // RTI has granted tag advance to an earlier tag or the wait // for the RTI response was interrupted by a local physical action with // a tag earlier than requested. @@ -644,12 +644,12 @@ void _lf_next_locked() { next_tag = get_next_event_tag(); // If this (possibly new) next tag is past the stop time, return. - if (_lf_is_tag_after_stop_tag(next_tag)) { // compare_tags(tag, stop_tag) > 0 + if (_lf_is_tag_after_stop_tag(next_tag)) { // lf_compare_tags(tag, stop_tag) > 0 return; } DEBUG_PRINT("Physical time is ahead of next tag time by %lld. This should be small unless -fast is used.", - get_physical_time() - next_tag.time); + lf_time(LF_PHYSICAL) - next_tag.time); #ifdef FEDERATED // In federated execution (at least under decentralized coordination), @@ -670,7 +670,7 @@ void _lf_next_locked() { // executed microstep 0 at the timeout time), then we are done. The above code prevents the next_tag // from exceeding the stop_tag, so we have to do further checks if // they are equal. - if (compare_tags(next_tag, stop_tag) >= 0 && compare_tags(current_tag, stop_tag) >= 0) { + if (lf_compare_tags(next_tag, stop_tag) >= 0 && lf_compare_tags(current_tag, stop_tag) >= 0) { // If we pop anything further off the event queue with this same time or larger, // then it will be assigned a tag larger than the stop tag. return; @@ -684,7 +684,7 @@ void _lf_next_locked() { // Advance current time to match that of the first event on the queue. _lf_advance_logical_time(next_tag.time); - if (compare_tags(current_tag, stop_tag) >= 0) { + if (lf_compare_tags(current_tag, stop_tag) >= 0) { // Pop shutdown events DEBUG_PRINT("Scheduling shutdown reactions."); _lf_trigger_shutdown_reactions(); @@ -707,7 +707,7 @@ void _lf_next_locked() { void request_stop() { lf_mutex_lock(&mutex); // Check if already at the previous stop tag. - if (compare_tags(current_tag, stop_tag) >= 0) { + if (lf_compare_tags(current_tag, stop_tag) >= 0) { // If so, ignore the stop request since the program // is already stopping at the current tag. lf_mutex_unlock(&mutex); @@ -783,7 +783,7 @@ void _lf_initialize_start_tag() { // If the stop_tag is (0,0), also insert the shutdown // reactions. This can only happen if the timeout time // was set to 0. - if (compare_tags(current_tag, stop_tag) >= 0) { + if (lf_compare_tags(current_tag, stop_tag) >= 0) { _lf_trigger_shutdown_reactions(); } @@ -828,10 +828,10 @@ void _lf_initialize_start_tag() { while (!wait_until(start_time, &event_q_changed)) {} DEBUG_PRINT("Done waiting for start time %lld.", start_time); DEBUG_PRINT("Physical time is ahead of current time by %lld. This should be small.", - get_physical_time() - start_time); + lf_time(LF_PHYSICAL) - start_time); // Reinitialize the physical start time to match the start_time. - // Otherwise, reports of get_elapsed_physical_time are not very meaningful + // Otherwise, reports of lf_time(LF_PHYSICAL) are not very meaningful // w.r.t. logical time. physical_start_time = start_time; #endif @@ -873,7 +873,7 @@ bool _lf_worker_handle_deadline_violation_for_reaction(int worker_number, reacti // then the reaction will be invoked and the violation reaction will not be invoked again. if (reaction->deadline > 0LL) { // Get the current physical time. - instant_t physical_time = get_physical_time(); + instant_t physical_time = lf_time(LF_PHYSICAL); // Check for deadline violation. if (physical_time > current_tag.time + reaction->deadline) { // Deadline violation has occurred. diff --git a/core/threaded/scheduler_sync_tag_advance.c b/core/threaded/scheduler_sync_tag_advance.c index 4572be326..fa574aa0b 100644 --- a/core/threaded/scheduler_sync_tag_advance.c +++ b/core/threaded/scheduler_sync_tag_advance.c @@ -74,7 +74,7 @@ bool _lf_sched_should_stop_locked() { logical_tag_complete(current_tag); // If we are at the stop tag, do not call _lf_next_locked() // to prevent advancing the logical time. - if (compare_tags(current_tag, stop_tag) >= 0) { + if (lf_compare_tags(current_tag, stop_tag) >= 0) { return true; } } diff --git a/core/trace.c b/core/trace.c index 379b0d6a8..048de7506 100644 --- a/core/trace.c +++ b/core/trace.c @@ -127,7 +127,7 @@ int write_trace_header() { lf_mutex_lock(&_lf_trace_mutex); // The first item in the header is the start time. // This is both the starting physical time and the starting logical time. - instant_t start_time = get_start_time(); + instant_t start_time = lf_time(LF_START); // printf("DEBUG: Start time written to trace file is %lld.\n", start_time); size_t items_written = fwrite( &start_time, @@ -368,7 +368,7 @@ void start_trace(char* filename) { * @param worker The thread number of the worker thread or 0 for unthreaded execution * or -1 for an unknown thread. * @param physical_time If the caller has already accessed physical time, provide it here. - * Otherwise, provide NULL. This argument avoids a second call to get_physical_time + * Otherwise, provide NULL. This argument avoids a second call to lf_time(LF_PHYSICAL) * and ensures that the physical time in the trace is the same as that used by the caller. * @param trigger Pointer to the trigger_t struct for calls to schedule or NULL otherwise. * @param extra_delay The extra delay passed to schedule(). If not relevant for this event @@ -397,12 +397,12 @@ void tracepoint( _lf_trace_buffer[index][i].pointer = pointer; _lf_trace_buffer[index][i].reaction_number = reaction_number; _lf_trace_buffer[index][i].worker = worker; - _lf_trace_buffer[index][i].logical_time = get_logical_time(); - _lf_trace_buffer[index][i].microstep = get_microstep(); + _lf_trace_buffer[index][i].logical_time = lf_time(LF_LOGICAL); + _lf_trace_buffer[index][i].microstep = lf_tag().microstep; if (physical_time != NULL) { _lf_trace_buffer[index][i].physical_time = *physical_time; } else { - _lf_trace_buffer[index][i].physical_time = get_physical_time(); + _lf_trace_buffer[index][i].physical_time = lf_time(LF_PHYSICAL); } _lf_trace_buffer_size[index]++; _lf_trace_buffer[index][i].trigger = trigger; diff --git a/core/trace.h b/core/trace.h index 868109b79..2dcb1fd72 100644 --- a/core/trace.h +++ b/core/trace.h @@ -155,7 +155,7 @@ void start_trace(char* filename); * @param reaction_number The index of the reaction or -1 if the trace is not of a reaction. * @param worker The thread number of the worker thread or 0 for unthreaded execution. * @param physical_time If the caller has already accessed physical time, provide it here. - * Otherwise, provide NULL. This argument avoids a second call to get_physical_time + * Otherwise, provide NULL. This argument avoids a second call to lf_time(LF_PHYSICAL) * and ensures that the physical time in the trace is the same as that used by the caller. * @param trigger Pointer to the trigger_t struct for calls to schedule or NULL otherwise. * @param extra_delay The extra delay passed to schedule(). If not relevant for this event diff --git a/include/ctarget.h b/include/ctarget_schedule.h similarity index 58% rename from include/ctarget.h rename to include/ctarget_schedule.h index 3aea626be..be646cf52 100644 --- a/include/ctarget.h +++ b/include/ctarget_schedule.h @@ -38,145 +38,37 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CTARGET_H -#define CTARGET_H - +#ifndef CTARGET_SCHEDULE +#define CTARGET_SCHEDULE #include "core/reactor.h" - -////////////////////////////////////////////////////////////// -///////////// SET Functions (to produce an output) - -// NOTE: According to the "Swallowing the Semicolon" section on this page: -// https://gcc.gnu.org/onlinedocs/gcc-3.0.1/cpp_3.html -// the following macros should use an odd do-while construct to avoid -// problems with if ... else statements that do not use braces around the -// two branches. - -/** - * Set the specified output (or input of a contained reactor) - * to the specified value. - * - * This version is used for primitive types such as int, - * double, etc. as well as the built-in types bool and string. - * The value is copied and therefore the variable carrying the - * value can be subsequently modified without changing the output. - * This can also be used for structs with a type defined by a typedef - * so that the type designating string does not end in '*'. - * @param out The output port (by name) or input of a contained - * reactor in form input_name.port_name. - * @param value The value to insert into the self struct. - */ -#define SET(out, val) _LF_SET(out, val) - -/** - * Version of set for output types given as 'type[]' where you - * want to send a previously dynamically allocated array. - * - * The deallocation is delegated to downstream reactors, which - * automatically deallocate when the reference count drops to zero. - * It also sets the corresponding _is_present variable in the self - * struct to true (which causes the object message to be sent). - * @param out The output port (by name). - * @param val The array to send (a pointer to the first element). - * @param length The length of the array to send. - * @see lf_token_t - */ -#define SET_ARRAY(out, val, element_size, length) _LF_SET_ARRAY(out, val, element_size, length) - -/** - * Version of set() for output types given as 'type*' that - * allocates a new object of the type of the specified output port. - * - * This macro dynamically allocates enough memory to contain one - * instance of the output datatype and sets the variable named - * by the argument to point to the newly allocated memory. - * The user code can then populate it with whatever value it - * wishes to send. - * - * This macro also sets the corresponding _is_present variable in the self - * struct to true (which causes the object message to be sent), - * @param out The output port (by name). - */ -#define SET_NEW(out) _LF_SET_NEW(out) - -/** - * Version of set() for output types given as 'type[]'. - * - * This allocates a new array of the specified length, - * sets the corresponding _is_present variable in the self struct to true - * (which causes the array message to be sent), and sets the variable - * given by the first argument to point to the new array so that the - * user code can populate the array. The freeing of the dynamically - * allocated array will be handled automatically - * when the last downstream reader of the message has finished. - * @param out The output port (by name). - * @param len The length of the array to be sent. - */ -#define SET_NEW_ARRAY(out, len) _LF_SET_NEW_ARRAY(out, len) - -/** - * Version of set() for output types given as 'type[number]'. - * - * This sets the _is_present variable corresponding to the specified output - * to true (which causes the array message to be sent). The values in the - * output are normally written directly to the array or struct before or - * after this is called. - * @param out The output port (by name). - */ -#define SET_PRESENT(out) _LF_SET_PRESENT(out) - -/** - * Version of set() for output types given as 'type*' or 'type[]' where you want - * to forward an input or action without copying it. - * - * The deallocation of memory is delegated to downstream reactors, which - * automatically deallocate when the reference count drops to zero. - * @param out The output port (by name). - * @param token A pointer to token obtained from an input or action. - */ -#define SET_TOKEN(out, newtoken) _LF_SET_TOKEN(out, newtoken) - -////////////////////////////////////////////////////////////// -///////////// SET_MODE Function (to switch a mode) - -/** - * Sets the next mode of a modal reactor. Same as SET for outputs, only - * the last value will have effect if invoked multiple times. - * Works only in reactions with the target mode declared as effect. - * - * @param mode The target mode to set for activation. - */ -#ifdef MODAL_REACTORS -#define SET_MODE(mode) _LF_SET_MODE(mode) -#endif - ////////////////////////////////////////////////////////////// ///////////// Schedule Functions - /** * Schedule an action to occur with the specified value and time offset * with no payload (no value conveyed). - * See schedule_token(), which this uses, for details. + * See lf_schedule_token(), which this uses, for details. * * @param action Pointer to an action on the self struct. * @param offset The time offset over and above that in the action. * @return A handle to the event, or 0 if no event was scheduled, or -1 for error. */ -trigger_handle_t schedule(void* action, interval_t offset); +trigger_handle_t lf_schedule(void* action, interval_t offset); +DEPRECATED(trigger_handle_t schedule(void* action, interval_t offset)); /** * Schedule the specified action with an integer value at a later logical * time that depends on whether the action is logical or physical and * what its parameter values are. This wraps a copy of the integer value - * in a token. See schedule_token() for more details. + * in a token. See lf_schedule_token() for more details. * * @param action The action to be triggered. * @param extra_delay Extra offset of the event release above that in the action. * @param value The value to send. * @return A handle to the event, or 0 if no event was scheduled, or -1 for error. */ -trigger_handle_t schedule_int(void* action, interval_t extra_delay, int value); +trigger_handle_t lf_schedule_int(void* action, interval_t extra_delay, int value); +DEPRECATED(trigger_handle_t schedule_int(void* action, interval_t extra_delay, int value)); /** * Schedule the specified action with the specified token as a payload. @@ -228,7 +120,8 @@ trigger_handle_t schedule_int(void* action, interval_t extra_delay, int value); * @param token The token to carry the payload or null for no payload. * @return A handle to the event, or 0 if no event was scheduled, or -1 for error. */ -trigger_handle_t schedule_token(void* action, interval_t extra_delay, lf_token_t* token); +trigger_handle_t lf_schedule_token(void* action, interval_t extra_delay, lf_token_t* token); +DEPRECATED(trigger_handle_t schedule_token(void* action, interval_t extra_delay, lf_token_t* token)); /** * Schedule an action to occur with the specified value and time offset with a @@ -237,7 +130,7 @@ trigger_handle_t schedule_token(void* action, interval_t extra_delay, lf_token_t * the trigger's token object's element_size field multiplied by the specified * length. * - * See schedule_token(), which this uses, for details. + * See lf_schedule_token(), which this uses, for details. * * @param action Pointer to an action on a self struct. * @param offset The time offset over and above that in the action. @@ -246,14 +139,15 @@ trigger_handle_t schedule_token(void* action, interval_t extra_delay, lf_token_t * @return A handle to the event, or 0 if no event was scheduled, or -1 for * error. */ -trigger_handle_t schedule_copy(void* action, interval_t offset, void* value, int length); +trigger_handle_t lf_schedule_copy(void* action, interval_t offset, void* value, int length); +DEPRECATED(trigger_handle_t schedule_copy(void* action, interval_t offset, void* value, int length)); /** - * Variant of schedule_token that creates a token to carry the specified value. + * Variant of lf_schedule_token that creates a token to carry the specified value. * The value is required to be malloc'd memory with a size equal to the * element_size of the specifies action times the length parameter. * - * See schedule_token(), which this uses, for details. + * See lf_schedule_token(), which this uses, for details. * * @param action The action to be triggered. * @param extra_delay Extra offset of the event release above that in the @@ -264,7 +158,8 @@ trigger_handle_t schedule_copy(void* action, interval_t offset, void* value, int * @return A handle to the event, or 0 if no event was scheduled, or -1 for * error. */ -trigger_handle_t schedule_value(void* action, interval_t extra_delay, void* value, int length); +trigger_handle_t lf_schedule_value(void* action, interval_t extra_delay, void* value, int length); +DEPRECATED(trigger_handle_t schedule_value(void* action, interval_t extra_delay, void* value, int length)); /** * Check the deadline of the currently executing reaction against the @@ -277,6 +172,7 @@ trigger_handle_t schedule_value(void* action, interval_t extra_delay, void* valu * handler if the deadline has passed. * @return True if the specified deadline has passed and false otherwise. */ -bool check_deadline(void* self, bool invoke_deadline_handler); +bool lf_check_deadline(void* self, bool invoke_deadline_handler); +DEPRECATED(bool check_deadline(void* self, bool invoke_deadline_handler)); -#endif // CTARGET_H +#endif // CTARGET_SCHEDULE diff --git a/include/ctarget_set.h b/include/ctarget_set.h new file mode 100644 index 000000000..c43c4086e --- /dev/null +++ b/include/ctarget_set.h @@ -0,0 +1,213 @@ +/** + * @file + * @author Edward A. Lee (eal@berkeley.edu) + * + * @section LICENSE +Copyright (c) 2020, The University of California at Berkeley. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * @section DESCRIPTION + * Target-specific runtime functions for the C target language. + * This API layer can be used in conjunction with: + * target C; + * + * Note for target language developers. This is one way of developing a target language where + * the C core runtime is adopted. This file is a translation layer that implements Lingua Franca + * APIs which interact with the internal _lf_SET and _lf_schedule APIs. This file can act as a + * template for future runtime developement for target languages. + * For source generation, see xtext/org.icyphy.linguafranca/src/org/icyphy/generator/CCppGenerator.xtend. + */ + +#ifndef CTARGET_SET +#define CTARGET_SET + +////////////////////////////////////////////////////////////// +///////////// SET Functions (to produce an output) + +// NOTE: According to the "Swallowing the Semicolon" section on this page: +// https://gcc.gnu.org/onlinedocs/gcc-3.0.1/cpp_3.html +// the following macros should use an odd do-while construct to avoid +// problems with if ... else statements that do not use braces around the +// two branches. + +/** + * Set the specified output (or input of a contained reactor) + * to the specified value. + * + * If the value argument is a primitive type such as int, + * double, etc. as well as the built-in types bool and string, + * the value is copied and therefore the variable carrying the + * value can be subsequently modified without changing the output. + * This also applies to structs with a type defined by a typedef + * so that the type designating string does not end in '*'. + * + * If the value argument is a pointer + * to memory that the calling reaction has dynamically allocated, + * the memory will be automatically freed once all downstream + * reactions no longer need the value. + * If 'lf_set_destructor' is called on 'out', then that destructor + * will be used to free 'value'. + * Otherwise, the default void free(void*) function is used. + * + * @param out The output port (by name) or input of a contained + * reactor in form input_name.port_name. + * @param value The value to insert into the self struct. + */ +#define lf_set(out, val) _LF_SET(out, val) +#define SET(out, val) \ +do { \ + _Pragma ("Warning \"'SET' is deprecated. Use 'lf_set' instead.\""); \ + _LF_SET(out, val); \ +} while (0) + +/** + * Version of lf_set for output types given as 'type[]' where you + * want to send a previously dynamically allocated array. + * + * The deallocation is delegated to downstream reactors, which + * automatically deallocate when the reference count drops to zero. + * It also sets the corresponding _is_present variable in the self + * struct to true (which causes the object message to be sent). + * @param out The output port (by name). + * @param val The array to send (a pointer to the first element). + * @param length The length of the array to send. + * @see lf_token_t + */ +#define SET_ARRAY(out, val, elem_size, length) \ +do { \ + _Pragma ("Warning \"'SET_ARRAY' is deprecated. Use 'lf_set_array' instead.\""); \ + _LF_SET_ARRAY(out, val, length); \ +} while (0) + +/** + * Version of lf_set() for output types given as 'type*' that + * allocates a new object of the type of the specified output port. + * + * This macro dynamically allocates enough memory to contain one + * instance of the output datatype and sets the variable named + * by the argument to point to the newly allocated memory. + * The user code can then populate it with whatever value it + * wishes to send. + * + * This macro also sets the corresponding _is_present variable in the self + * struct to true (which causes the object message to be sent), + * @param out The output port (by name). + */ +#define SET_NEW(out) \ +do { \ + _Pragma ("Warning \"'SET_NEW' is deprecated. Use 'lf_set_new' instead.\""); \ + _LF_SET_NEW(out); \ +} while (0) + +/** + * Version of lf_set() for output types given as 'type[]'. + * + * This allocates a new array of the specified length, + * sets the corresponding _is_present variable in the self struct to true + * (which causes the array message to be sent), and sets the variable + * given by the first argument to point to the new array so that the + * user code can populate the array. The freeing of the dynamically + * allocated array will be handled automatically + * when the last downstream reader of the message has finished. + * @param out The output port (by name). + * @param len The length of the array to be sent. + */ +#define SET_NEW_ARRAY(out, len) \ +do { \ + _Pragma ("Warning \"'SET_NEW_ARRAY' is deprecated. Use 'lf_set_new_array' instead.\""); \ + _LF_SET_NEW_ARRAY(out, len); \ +} while (0) + +/** + * Version of lf_set() for output types given as 'type[number]'. + * + * This sets the _is_present variable corresponding to the specified output + * to true (which causes the array message to be sent). The values in the + * output are normally written directly to the array or struct before or + * after this is called. + * @param out The output port (by name). + */ +#define SET_PRESENT(out) \ +do { \ + _Pragma ("Warning \"'SET_PRESENT' is deprecated. Use 'lf_set_present' instead.\""); \ + _LF_SET_PRESENT(out); \ +} while (0) + +/** + * Version of lf_set() for output types given as 'type*' or 'type[]' where you want + * to forward an input or action without copying it. + * + * The deallocation of memory is delegated to downstream reactors, which + * automatically deallocate when the reference count drops to zero. + * @param out The output port (by name). + * @param token A pointer to token obtained from an input or action. + */ +#define lf_set_token(out, newtoken) _LF_SET_TOKEN(out, newtoken) +#define SET_TOKEN(out, newtoken) \ +do { \ + _Pragma ("Warning \"'SET_TOKEN' is deprecated. Use 'lf_set_token' instead.\""); \ + _LF_SET_TOKEN(out, newtoken); \ +} while (0) + +/** + * Set the destructor used to free "token->value" set on "out". + * That memory will be automatically freed once all downstream + * reactions no longer need the value. + * + * @param out The output port (by name) or input of a contained + * reactor in form input_name.port_name. + * @param dtor A pointer to a void function that takes a pointer argument + * or NULL to use the default void free(void*) function. + */ +#define lf_set_destructor(out, dtor) _LF_SET_DESTRUCTOR(out, dtor) + +/** + * Set the destructor used to copy construct "token->value" received + * by "in" if "in" is mutable. + * + * @param out The output port (by name) or input of a contained + * reactor in form input_name.port_name. + * @param cpy_ctor A pointer to a void* function that takes a pointer argument + * or NULL to use the memcpy operator. + */ +#define lf_set_copy_constructor(out, cpy_ctor) _LF_SET_COPY_CONSTRUCTOR(out, cpy_ctor) + +////////////////////////////////////////////////////////////// +///////////// SET_MODE Function (to switch a mode) + +/** + * Sets the next mode of a modal reactor. Same as SET for outputs, only + * the last value will have effect if invoked multiple times. + * Works only in reactions with the target mode declared as effect. + * + * @param mode The target mode to set for activation. + */ +#ifdef MODAL_REACTORS +#define lf_set_mode(mode) _LF_SET_MODE(mode) +#define SET_MODE(mode) \ +do { \ + _Pragma ("Warning \"'SET_MODE' is deprecated. Use 'lf_set_mode' instead.\""); \ + _LF_SET_MODE(mode); \ +} while (0) +#endif // MODAL_REACTORS + +#endif // CTARGET_SET \ No newline at end of file diff --git a/include/ctarget_set_undef.h b/include/ctarget_set_undef.h new file mode 100644 index 000000000..da1a1c180 --- /dev/null +++ b/include/ctarget_set_undef.h @@ -0,0 +1,115 @@ +/** + * @file + * @author Hou Seng Wong (housengw@berkeley.edu) + * + * @section LICENSE +Copyright (c) 2022, The University of California at Berkeley. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * @section DESCRIPTION + * Undefining the macros in the ctarget_set.h + * Refer to ctarget_set.h for details of the macros + * + * Note for target language developers. This is one way of developing a target language where + * the C core runtime is adopted. This file is a translation layer that implements Lingua Franca + * APIs which interact with the internal _lf_SET and _lf_schedule APIs. This file can act as a + * template for future runtime developement for target languages. + * For source generation, see xtext/org.icyphy.linguafranca/src/org/icyphy/generator/CCppGenerator.xtend. + */ + + +#ifdef CTARGET_SET +#undef CTARGET_SET + +////////////////////////////////////////////////////////////// +///////////// SET Functions (to produce an output) + +// NOTE: According to the "Swallowing the Semicolon" section on this page: +// https://gcc.gnu.org/onlinedocs/gcc-3.0.1/cpp_3.html +// the following macros should use an odd do-while construct to avoid +// problems with if ... else statements that do not use braces around the +// two branches. + +/** + * Set the specified output (or input of a contained reactor) + * to the specified value. + */ +#undef lf_set +#undef SET + +/** + * Version of lf_set for output types given as 'type[]' where you + * want to send a previously dynamically allocated array. + */ +#undef SET_ARRAY + +/** + * Version of lf_set() for output types given as 'type*' that + * allocates a new object of the type of the specified output port. + */ +#undef SET_NEW + +/** + * Version of lf_set() for output types given as 'type[]'. + */ +#undef SET_NEW_ARRAY + +/** + * Version of lf_set() for output types given as 'type[number]'. + */ +#undef SET_PRESENT + +/** + * Version of lf_set() for output types given as 'type*' or 'type[]' where you want + * to forward an input or action without copying it. + */ +#undef lf_set_token +#undef SET_TOKEN + +/** + * Set the destructor used to free "token->value" set on "out". + * That memory will be automatically freed once all downstream + * reactions no longer need the value. + */ +#undef lf_set_destructor + + +/** + * Set the destructor used to copy construct "token->value" received + * by "in" if "in" is mutable. + */ +#undef lf_set_copy_constructor + +////////////////////////////////////////////////////////////// +///////////// SET_MODE Function (to switch a mode) + +/** + * Sets the next mode of a modal reactor. Same as SET for outputs, only + * the last value will have effect if invoked multiple times. + * Works only in reactions with the target mode declared as effect. + */ +#ifdef MODAL_REACTORS +#undef lf_set_mode +#undef SET_MODE +#endif + +#endif // CTARGET_SET \ No newline at end of file diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 735d2b1db..ea66640f8 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,4 +1,4 @@ -set(SOURCES ctarget.c) +set(SOURCES ctarget_schedule.c) -add_library(lib ctarget.c) +add_library(lib ctarget_schedule.c) target_include_directories(lib PRIVATE ${PROJECT_SOURCE_DIR}/include) diff --git a/lib/ctarget.c b/lib/ctarget_schedule.c similarity index 87% rename from lib/ctarget.c rename to lib/ctarget_schedule.c index d796f4698..3148fc141 100644 --- a/lib/ctarget.c +++ b/lib/ctarget_schedule.c @@ -37,7 +37,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * For source generation, see xtext/org.icyphy.linguafranca/src/org/icyphy/generator/CCppGenerator.xtend. */ -#include "ctarget.h" +#include "ctarget_schedule.h" /** * Schedule an action to occur with the specified value and time offset @@ -48,10 +48,17 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @param offset The time offset over and above that in the action. * @return A handle to the event, or 0 if no event was scheduled, or -1 for error. */ -trigger_handle_t schedule(void* action, interval_t offset) { +trigger_handle_t lf_schedule(void* action, interval_t offset) { return _lf_schedule_token(action, offset, NULL); } +/** + * @deprecated version of 'lf_schedule' + */ +trigger_handle_t schedule(void* action, interval_t offset) { + return lf_schedule(action, offset); +} + /** * Schedule the specified action with an integer value at a later logical * time that depends on whether the action is logical or physical and @@ -63,11 +70,19 @@ trigger_handle_t schedule(void* action, interval_t offset) { * @param value The value to send. * @return A handle to the event, or 0 if no event was scheduled, or -1 for error. */ -trigger_handle_t schedule_int(void* action, interval_t extra_delay, int value) +trigger_handle_t lf_schedule_int(void* action, interval_t extra_delay, int value) { return _lf_schedule_int(action, extra_delay, value); } +/** + * @deprecated version of 'lf_schedule_int' + */ +trigger_handle_t schedule_int(void* action, interval_t extra_delay, int value) +{ + return lf_schedule_int(action, extra_delay, value); +} + /** * Schedule the specified action with the specified token as a payload. * This will trigger an event at a later logical time that depends @@ -118,10 +133,17 @@ trigger_handle_t schedule_int(void* action, interval_t extra_delay, int value) * @param token The token to carry the payload or null for no payload. * @return A handle to the event, or 0 if no event was scheduled, or -1 for error. */ -trigger_handle_t schedule_token(void* action, interval_t extra_delay, lf_token_t* token) { +trigger_handle_t lf_schedule_token(void* action, interval_t extra_delay, lf_token_t* token) { return _lf_schedule_token(action, extra_delay, token); } +/** + * @deprecated version of 'lf_schedule_token' + */ +trigger_handle_t schedule_token(void* action, interval_t extra_delay, lf_token_t* token) { + return lf_schedule_token(action, extra_delay, token); +} + /** * Schedule an action to occur with the specified value and time offset with a * copy of the specified value. If the value is non-null, then it will be copied @@ -138,7 +160,7 @@ trigger_handle_t schedule_token(void* action, interval_t extra_delay, lf_token_t * @return A handle to the event, or 0 if no event was scheduled, or -1 for * error. */ -trigger_handle_t schedule_copy(void* action, interval_t offset, void* value, int length) { +trigger_handle_t lf_schedule_copy(void* action, interval_t offset, void* value, int length) { if (length < 0) { error_print( "schedule_copy():" @@ -150,6 +172,13 @@ trigger_handle_t schedule_copy(void* action, interval_t offset, void* value, int return _lf_schedule_copy(action, offset, value, (size_t)length); } +/** + * @deprecated version of 'lf_schedule_copy' + */ +trigger_handle_t schedule_copy(void* action, interval_t offset, void* value, int length) { + return lf_schedule_copy(action, offset, value, length); +} + /** * Variant of schedule_token that creates a token to carry the specified value. @@ -167,7 +196,7 @@ trigger_handle_t schedule_copy(void* action, interval_t offset, void* value, int * @return A handle to the event, or 0 if no event was scheduled, or -1 for * error. */ -trigger_handle_t schedule_value(void* action, interval_t extra_delay, void* value, int length) { +trigger_handle_t lf_schedule_value(void* action, interval_t extra_delay, void* value, int length) { if (length < 0) { error_print( "schedule_value():" @@ -179,6 +208,14 @@ trigger_handle_t schedule_value(void* action, interval_t extra_delay, void* valu return _lf_schedule_value(action, extra_delay, value, (size_t)length); } +/** + * @deprecated version of 'lf_schedule_value' + */ +trigger_handle_t schedule_value(void* action, interval_t extra_delay, void* value, int length) { + return lf_schedule_value(action, extra_delay, value, length); +} + + /** * Check the deadline of the currently executing reaction against the * current physical time. If the deadline has passed, invoke the deadline @@ -190,6 +227,13 @@ trigger_handle_t schedule_value(void* action, interval_t extra_delay, void* valu * handler if the deadline has passed. * @return True if the specified deadline has passed and false otherwise. */ -bool check_deadline(void* self, bool invoke_deadline_handler) { +bool lf_check_deadline(void* self, bool invoke_deadline_handler) { return _lf_check_deadline((self_base_t*)self, invoke_deadline_handler); } + +/** + * @deprecated version of 'lf_check_deadline' + */ +bool check_deadline(void* self, bool invoke_deadline_handler) { + return lf_check_deadline(self, invoke_deadline_handler); +} diff --git a/lingua-franca-ref.txt b/lingua-franca-ref.txt index 9d96fbbf1..3ea7956a8 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -6750a7c3ae38fb70551c36d05cc5431799e522cd +767b3c3ef8e8a89c319c193a2d8109938943df38 \ No newline at end of file diff --git a/util/audio_loop_linux.c b/util/audio_loop_linux.c index f52370829..8eeb898ef 100644 --- a/util/audio_loop_linux.c +++ b/util/audio_loop_linux.c @@ -392,7 +392,7 @@ int lf_play_audio_waveform(lf_waveform_t* waveform, float emphasis, instant_t st // occur. while (index_offset >= AUDIO_BUFFER_SIZE) { pthread_cond_wait(&lf_audio_cond, &lf_audio_mutex); - time_offset = get_logical_time() - next_buffer_start_time; + time_offset = lf_time(LF_LOGICAL) - next_buffer_start_time; index_offset = (time_offset * SAMPLE_RATE) / BILLION; } diff --git a/util/audio_loop_mac.c b/util/audio_loop_mac.c index f8af74a29..e76a574a9 100644 --- a/util/audio_loop_mac.c +++ b/util/audio_loop_mac.c @@ -283,7 +283,7 @@ int lf_play_audio_waveform(lf_waveform_t* waveform, float emphasis, instant_t st // occur. while (index_offset >= AUDIO_BUFFER_SIZE) { pthread_cond_wait(&lf_audio_cond, &lf_audio_mutex); - time_offset = get_logical_time() - next_buffer_start_time; + time_offset = lf_time(LF_LOGICAL) - next_buffer_start_time; index_offset = (time_offset * SAMPLE_RATE) / BILLION; } diff --git a/util/sensor_simulator.c b/util/sensor_simulator.c index 60033b2e9..60f0c882c 100644 --- a/util/sensor_simulator.c +++ b/util/sensor_simulator.c @@ -33,7 +33,7 @@ See sensor_simulator.h. #include #include #include "sensor_simulator.h" -#include "ctarget.h" +#include "ctarget_schedule.h" #include "core/utils/util.h" #include "core/platform.h"