1 /* 2 * Generation of server dispatch and handle functions. 3 * 4 * Copyright (C) 2019, 2022 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <stdlib.h> 23 #include "common.h" 24 #include "dispatch.h" 25 #include "templates.h" 26 27 28 29 /* Generate each dispatch possibility within an interface. */ 30 31 static void write_dispatcher_cases(FILE *fp, struct interface *iface, 32 int compound) 33 { 34 struct signature *sig; 35 char *opcode, *opname, *protocol, *prefix, *ref, *s; 36 37 for (sig = iface->signatures; sig != NULL; sig = sig->tail) 38 { 39 opname = get_operation_name(iface, sig); 40 opcode = get_opcode_identifier(NULL, opname); 41 prefix = get_operation_wrapper_prefix(sig->attributes); 42 43 /* Convert to any base interface. */ 44 45 ref = get_object_conversion(iface, compound); 46 47 /* Generate a reply if appropriate. */ 48 49 if (have_attribute(sig->attributes, "completion")) 50 s = dispatch_function_wrapper_case; 51 else 52 s = dispatch_function_reply_wrapper_case; 53 54 /* Generate the case and invocation. */ 55 56 fprintf(fp, s, opcode, prefix, opname, ref); 57 58 /* Free allocated strings. */ 59 60 free(opcode); 61 free(opname); 62 free(ref); 63 } 64 } 65 66 /* Dispatch to each interface-level function where the same protocol applies to 67 an entire interface. Dispatch to each operation where an interface does not 68 specify a protocol. */ 69 70 static void write_dispatcher_interface_cases(FILE *fp, struct interface *iface, 71 int by_protocol) 72 { 73 struct interface_ref *base; 74 char *protocol, *ref; 75 76 for (base = iface->bases; base != NULL; base = base->tail) 77 { 78 protocol = get_protocol(base->iface->attributes); 79 80 /* Write cases for each interface, using the protocol to select between the 81 cases. */ 82 83 if (by_protocol && (protocol != NULL)) 84 { 85 /* Convert to any base interface. */ 86 87 ref = get_object_conversion(base->iface, 1); 88 fprintf(fp, dispatch_function_interface_case, protocol, base->name, ref); 89 free(ref); 90 } 91 92 /* Write cases for each operation provided by the interface so that they can 93 be selected. Note that this requires distinct opcodes to be used, so in 94 practice requiring explicit opcodes to be indicated. */ 95 96 else if (!by_protocol && (protocol == NULL)) 97 write_dispatcher_cases(fp, base->iface, 1); 98 } 99 } 100 101 /* Return whether any base interface specifies a protocol. */ 102 103 static int have_interfaces_using_protocols(struct interface *iface) 104 { 105 struct interface_ref *base; 106 107 for (base = iface->bases; base != NULL; base = base->tail) 108 if (get_protocol(base->iface->attributes) != NULL) 109 return 1; 110 111 return 0; 112 } 113 114 115 116 /* Generate dispatch function signatures. */ 117 118 void write_dispatcher_signature(const char *name, enum signature_role role, 119 FILE *fp) 120 { 121 fprintf(fp, dispatch_function_signature, name, name); 122 fputs(get_signature_terminator(role), fp); 123 } 124 125 /* Generate handler function signatures. */ 126 127 void write_handler_signature(const char *name, enum signature_role role, 128 FILE *fp) 129 { 130 fprintf(fp, handle_function_signature, name, name); 131 fputs(get_signature_terminator(role), fp); 132 } 133 134 /* Generate a dispatch function for the different operations. */ 135 136 void write_dispatcher(FILE *fp, struct interface *iface) 137 { 138 char *protocol = get_protocol(iface->attributes); 139 140 write_dispatcher_signature(iface->name, DEFINITION_ROLE, fp); 141 142 /* Declare an error variable to support testing for already-sent messages. */ 143 144 fputs(" long err;\n\n", fp); 145 146 /* Without a protocol applying to the entire interface, dispatch using the 147 protocol from the message label. */ 148 149 if (protocol == NULL) 150 { 151 fputs(" switch (l4_msgtag_label(msg->tag))\n {\n", fp); 152 153 /* Dispatch using the protocol to base interfaces employing protocols. */ 154 155 if (have_interfaces_using_protocols(iface)) 156 write_dispatcher_interface_cases(fp, iface, 1); 157 } 158 159 /* If a protocol applies to the entire interface, dispatch using an operation 160 indicator in the word data. */ 161 162 else 163 fputs(" switch (ipc_message_get_word(msg, 0))\n {\n", fp); 164 165 /* Dispatch to operations provided by compound interfaces. */ 166 167 write_dispatcher_interface_cases(fp, iface, 0); 168 169 /* Dispatch to each operation defined at this level. */ 170 171 write_dispatcher_cases(fp, iface, is_compound_interface(iface)); 172 173 /* Terminate the dispatcher. */ 174 175 fputs(dispatch_function_default_case, fp); 176 fputs(dispatch_function_dispatcher_epilogue, fp); 177 178 fputs(END_FUNCTION, fp); 179 }