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