1 /* 2 * Server code generation. 3 * 4 * Copyright (C) 2019, 2020 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 "config.h" 25 #include "declaration.h" 26 #include "message.h" 27 #include "server.h" 28 #include "templates.h" 29 30 31 32 /* Generate each component operation signature or "function prototype". */ 33 34 void write_server_interface_signature(struct signature *sig, 35 enum signature_role role, FILE *fp, 36 struct interface *iface) 37 { 38 write_interface_signature(sig, role, SERVER_ROLE, 39 get_server_function_role(sig), fp, iface); 40 41 /* Generate a signature for an ahead-of-time reply completion function. */ 42 43 write_interface_signature(sig, role, SERVER_ROLE, COMPLETION_REPLY_ROLE, fp, 44 iface); 45 } 46 47 /* Generate signature declarations for each operation. */ 48 49 void write_server_signature(struct signature *sig, enum signature_role role, 50 FILE *fp, struct interface *iface) 51 { 52 if (have_attribute(sig->attributes, "completion")) 53 write_server_initiation_signature(sig, role, fp, iface); 54 else 55 write_server_wrapper_signature(sig, role, fp, iface); 56 57 /* Write the appropriate completion signature even for use by conventional 58 operations. */ 59 60 write_server_completion_signature(sig, role, fp, iface); 61 } 62 63 /* Generic signature generation. */ 64 65 static void _write_server_signature(struct signature *sig, 66 enum signature_role role, 67 FILE *fp, struct interface *iface, 68 const char *prefix) 69 { 70 char *opname = get_operation_name(iface, sig); 71 72 fprintf(fp, server_function_signature, prefix, opname, iface->name); 73 fputs(get_signature_terminator(role), fp); 74 75 free(opname); 76 } 77 78 /* Generate operation wrapper function details used by the server. */ 79 80 void write_server_wrapper_signature(struct signature *sig, enum signature_role role, 81 FILE *fp, struct interface *iface) 82 { 83 _write_server_signature(sig, role, fp, iface, "wrap"); 84 } 85 86 void write_server_initiation_signature(struct signature *sig, 87 enum signature_role role, 88 FILE *fp, struct interface *iface) 89 { 90 _write_server_signature(sig, role, fp, iface, "initiate"); 91 } 92 93 void write_server_completion_signature(struct signature *sig, 94 enum signature_role role, 95 FILE *fp, struct interface *iface) 96 { 97 char *opname = get_operation_name(iface, sig); 98 99 /* Generate a signature featuring an initiator reference (for genuine 100 decoupled completions) and only "out" and "inout" parameters. */ 101 102 int completion = have_attribute(sig->attributes, "completion"); 103 104 char *prologue = completion ? 105 server_completion_function_signature_prologue : 106 server_completion_reply_function_signature_prologue; 107 108 fprintf(fp, prologue, opname, iface->name); 109 110 /* Continue from the initial endpoint parameter if a genuine completion. */ 111 112 write_parameters(sig->parameters, fp, SIGNATURE_ROLE, COMPLETION_ROLE, 113 OUT_PARAMETER, completion); 114 115 fputs(")", fp); 116 fputs(get_signature_terminator(role), fp); 117 118 free(opname); 119 } 120 121 /* Generate function source code for each operation, with the generated function 122 unpacking a message, calling the actual operation and repacking the 123 results. */ 124 125 void write_server_function(struct signature *sig, FILE *fp, struct interface *iface) 126 { 127 if (have_attribute(sig->attributes, "completion")) 128 { 129 write_server_initiation_signature(sig, DEFINITION_ROLE, fp, iface); 130 write_server_initiation_function_body(sig->parameters, fp, iface, sig); 131 fputs(END_FUNCTION, fp); 132 } 133 else 134 { 135 write_server_wrapper_signature(sig, DEFINITION_ROLE, fp, iface); 136 write_server_wrapper_function_body(sig->parameters, fp, iface, sig); 137 fputs(END_FUNCTION, fp); 138 } 139 140 /* Write the appropriate completion function even for use by conventional 141 operations. */ 142 143 write_server_completion_signature(sig, DEFINITION_ROLE, fp, iface); 144 write_server_completion_function_body(sig->parameters, fp, iface, sig); 145 fputs(END_FUNCTION, fp); 146 } 147 148 /* Generate a function body corresponding to an operation for server use. */ 149 150 void write_server_wrapper_function_body(struct parameter *param, FILE *fp, 151 struct interface *iface, struct signature *sig) 152 { 153 int input_words, input_items, output_words, output_items; 154 char *opname = get_operation_name(iface, sig); 155 156 /* Generate the prologue. */ 157 158 fputs(server_function_body_prologue, fp); 159 160 /* Count the number of input words, items and output words. */ 161 162 count_parameters(param, &input_words, &input_items, &output_words, &output_items); 163 164 /* Generate variable declarations. */ 165 166 write_declarations(param, ANY_PARAMETER, ANY_CLASS, fp); 167 168 /* Generate types parameterised with the qualified operation name. */ 169 170 write_accessor_declaration(input_words, output_words, opname, fp); 171 172 /* Handle superfluous message structures. */ 173 174 write_superfluous_message_cast(fp, input_words, input_items, output_words, output_items); 175 176 /* Unpack each word and item from the message into variables. */ 177 178 write_input_initialisation(param, fp, opname, input_words, input_items); 179 180 /* Invoke the actual operation using the variables. */ 181 182 write_server_function_call(param, fp, iface, sig, ANY_PARAMETER); 183 184 /* Pack the outputs into the message and perform any other housekeeping. */ 185 186 write_output_initialisation(param, fp, opname, output_words, output_items, GENERAL_FUNCTION_ROLE); 187 188 /* Return the success of the reply operation. */ 189 190 fputs(server_function_body_epilogue, fp); 191 192 /* Free allocated strings. */ 193 194 free(opname); 195 } 196 197 /* Generate a function body corresponding to the initiation of an operation. */ 198 199 void write_server_initiation_function_body(struct parameter *param, FILE *fp, 200 struct interface *iface, 201 struct signature *sig) 202 { 203 int input_words, input_items, output_words, output_items; 204 char *opname = get_operation_name(iface, sig); 205 206 /* Generate the prologue. */ 207 208 fputs(server_function_body_prologue, fp); 209 210 /* Count the number of input words, items and output words. */ 211 212 count_parameters(param, &input_words, &input_items, &output_words, &output_items); 213 214 /* Generate variable declarations for "in" and "inout" parameters. */ 215 216 write_declarations(param, IN_PARAMETER, ANY_CLASS, fp); 217 218 /* Generate types parameterised with the qualified operation name. */ 219 220 write_accessor_declaration(input_words, 0, opname, fp); 221 222 /* Handle superfluous message structures. */ 223 224 write_superfluous_message_cast(fp, input_words, input_items, 0, 0); 225 226 /* Unpack each word and item from the message into variables. */ 227 228 write_input_initialisation(param, fp, opname, input_words, input_items); 229 230 /* Invoke the actual operation using the variables. */ 231 232 write_server_function_call(param, fp, iface, sig, IN_PARAMETER); 233 234 /* Return the success of the operation restoring buffer registers. */ 235 236 fputs(server_initiation_function_body_epilogue, fp); 237 238 /* Free allocated strings. */ 239 240 free(opname); 241 } 242 243 /* Generate a function body corresponding to the completion of an operation. */ 244 245 void write_server_completion_function_body(struct parameter *param, FILE *fp, 246 struct interface *iface, 247 struct signature *sig) 248 { 249 int input_words, input_items, output_words, output_items; 250 char *opname = get_operation_name(iface, sig); 251 252 /* Generate the prologue. */ 253 254 fputs(server_completion_function_body_prologue, fp); 255 256 /* Count the number of input words, items and output words. */ 257 258 count_parameters(param, &input_words, &input_items, &output_words, &output_items); 259 260 /* Generate types parameterised with the qualified operation name. */ 261 262 write_accessor_declaration(0, output_words, opname, fp); 263 264 /* Initialise the message. */ 265 266 fprintf(fp, "\n ipc_message_new(&msg);\n"); 267 268 /* Pack the outputs into the message and perform any other housekeeping. */ 269 270 write_output_initialisation(param, fp, opname, output_words, output_items, COMPLETION_ROLE); 271 272 /* Send a response as a new message to the given endpoint. 273 NOTE: The label 0 is employed but an error condition could be communicated. */ 274 275 if (have_attribute(sig->attributes, "completion")) 276 fprintf(fp, server_completion_function_body_epilogue, "0", "_endp"); 277 278 /* Send a plain reply for reply/coupled completions. */ 279 280 else 281 fputs(server_completion_reply_function_body_epilogue, fp); 282 283 /* Free allocated strings. */ 284 285 free(opname); 286 } 287 288 /* Generate a cast for superfluous message structures. */ 289 290 void write_superfluous_message_cast(FILE *fp, int input_words, int input_items, 291 int output_words, int output_items) 292 { 293 if (!input_words && !input_items && !output_words && !output_items) 294 fputs(server_function_body_unused_message, fp); 295 } 296 297 /* Generate the initialisation of input words and items. */ 298 299 void write_input_initialisation(struct parameter *param, FILE *fp, 300 const char *opname, int input_words, 301 int input_items) 302 { 303 if (input_words) 304 { 305 write_accessor_initialisation(IN_PARAMETER, SERVER_ROLE, GENERAL_FUNCTION_ROLE, 306 opname, fp); 307 write_message_access(param, SERVER_ROLE, GENERAL_FUNCTION_ROLE, IN_PARAMETER, 308 WORD_CLASS, fp); 309 } 310 311 if (input_items) 312 { 313 fputs("\n", fp); 314 write_message_access(param, SERVER_ROLE, GENERAL_FUNCTION_ROLE, IN_PARAMETER, 315 ITEM_CLASS, fp); 316 } 317 } 318 319 /* Generate the initialisation of output words and items. */ 320 321 void write_output_initialisation(struct parameter *param, FILE *fp, 322 const char *opname, int output_words, 323 int output_items, enum function_role function) 324 { 325 if (output_words) 326 { 327 write_accessor_initialisation(OUT_PARAMETER, SERVER_ROLE, function, 328 opname, fp); 329 write_message_access(param, SERVER_ROLE, function, OUT_PARAMETER, 330 WORD_CLASS, fp); 331 } 332 333 if (output_items) 334 { 335 fputs("\n", fp); 336 write_message_access(param, SERVER_ROLE, function, OUT_PARAMETER, 337 ITEM_CLASS, fp); 338 } 339 } 340 341 /* Generate an invocation of the actual server operation. */ 342 343 void write_server_function_call(struct parameter *param, FILE *fp, 344 struct interface *iface, struct signature *sig, 345 enum specifier specifier) 346 { 347 int continuing = 0; 348 char *name, *addr, 349 *opname = get_signature_operation_name(iface, sig, SERVER_ROLE, 350 ACCESS_ROLE, conf.language); 351 352 fputs("\n err = ", fp); 353 354 /* Access a method when emitting C++. */ 355 356 if (conf.language == CPP_LANGUAGE) 357 fprintf(fp, "_self->%s(", opname); 358 359 /* Employ a function pointer via the object type otherwise. */ 360 361 else 362 { 363 fprintf(fp, "_self->iface->%s(_self->ref", opname); 364 continuing = 1; 365 } 366 367 /* Generate the parameter list, employing addresses for output parameters. */ 368 369 write_parameters(param, fp, INVOCATION_ROLE, GENERAL_FUNCTION_ROLE, specifier, 370 continuing); 371 fputs(");\n", fp); 372 373 /* Emit post-invocation details. */ 374 375 fputs(server_function_body_call, fp); 376 377 /* Free allocated strings. */ 378 379 free(opname); 380 }