Cygwin: Add new APIs tc[gs]etwinsize()
[newlib-cygwin.git] / newlib / libc / sys / amdgcn / write.c
blob39e28c1e6fa172a6565fc870a387b08d74bbbf82
1 /*
2 * Support file for amdgcn in newlib.
3 * Copyright (c) 2014, 2017 Mentor Graphics.
5 * The authors hereby grant permission to use, copy, modify, distribute,
6 * and license this software and its documentation for any purpose, provided
7 * that existing copyright notices are retained in all copies and that this
8 * notice is included verbatim in any distributions. No written agreement,
9 * license, or royalty fee is required for any of the authorized uses.
10 * Modifications to this software may be copyrighted by their authors
11 * and need not follow the licensing terms described here, provided that
12 * the new terms are clearly indicated on the first page of each file where
13 * they apply.
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include <string.h>
22 /* This struct must match the one used by gcn-run and libgomp.
23 It holds all the data output from a kernel (besides mapping data).
25 The base address pointer can be found at kernargs+16.
27 The next_output counter must be atomically incremented for each
28 print output. Only when the print data is fully written can the
29 "written" flag be set.
31 The buffer is circular; the host increments the consumed counter
32 and clears the written flag as it goes, opening up slots for reuse.
33 The counters always use absolute numbers. */
34 struct output {
35 int return_value;
36 unsigned int next_output;
37 struct printf_data {
38 int written;
39 char msg[128];
40 int type;
41 union {
42 int64_t ivalue;
43 double dvalue;
44 char text[128];
46 } queue[1024];
47 unsigned int consumed;
50 _READ_WRITE_RETURN_TYPE write (int fd, const void *buf, size_t count)
52 if (fd != 1 && fd != 2)
54 errno = EBADF;
55 return -1;
58 /* The output data is at ((void*)kernargs)[2]. */
59 #if defined(__has_builtin) && __has_builtin(__builtin_gcn_kernarg_ptr)
60 register void **kernargs = __builtin_gcn_kernarg_ptr ();
61 #else
62 register void **kernargs asm("s8");
63 #endif
64 struct output *data = (struct output *)kernargs[2];
66 /* Each output slot allows 256 bytes, so reserve as many as we need. */
67 unsigned int slot_count = ((count+1)/256)+1;
68 unsigned int index = __atomic_fetch_add (&data->next_output, slot_count,
69 __ATOMIC_ACQUIRE);
71 if ((unsigned int)(index + slot_count) < data->consumed)
73 /* Overflow. */
74 errno = EFBIG;
75 return 0;
78 for (int c = count;
79 c >= 0;
80 buf += 256, c -= 256, index++)
82 unsigned int slot = index % 1024;
84 /* Spinlock while the host catches up. */
85 if (index >= 1024)
86 while (__atomic_load_n (&data->consumed, __ATOMIC_ACQUIRE)
87 <= (index - 1024))
88 asm ("s_sleep 64");
90 if (c < 128)
92 memcpy (data->queue[slot].msg, buf, c);
93 data->queue[slot].msg[c] = '\0';
94 data->queue[slot].text[0] = '\0';
96 else if (c < 256)
98 memcpy (data->queue[slot].msg, buf, 128);
99 memcpy (data->queue[slot].text, buf+128, c-128);
100 data->queue[slot].text[c-128] = '\0';
102 else
104 memcpy (data->queue[slot].msg, buf, 128);
105 memcpy (data->queue[slot].text, buf+128, 128);
108 data->queue[slot].type = 3; /* Raw. */
109 __atomic_store_n (&data->queue[slot].written, 1, __ATOMIC_RELEASE);
112 return count;