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