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