Merge commit 'junio/master'
[git/platforms.git] / progress.c
blobf53d8251a3a33ca3e9d580382ecab98faa77b8f7
1 #include "git-compat-util.h"
2 #include "progress.h"
4 static volatile sig_atomic_t progress_update;
6 #ifndef __MINGW32__
7 static void progress_interval(int signum)
9 progress_update = 1;
11 #else
12 static HANDLE progress_event;
13 static HANDLE progress_thread;
15 static __stdcall unsigned heartbeat(void *dummy)
17 while (WaitForSingleObject(progress_event, 1000) == WAIT_TIMEOUT)
18 progress_update = 1;
19 return 0;
21 #endif
23 static void set_progress_signal(void)
25 #ifndef __MINGW32__
26 struct sigaction sa;
27 struct itimerval v;
29 progress_update = 0;
31 memset(&sa, 0, sizeof(sa));
32 sa.sa_handler = progress_interval;
33 sigemptyset(&sa.sa_mask);
34 sa.sa_flags = SA_RESTART;
35 sigaction(SIGALRM, &sa, NULL);
37 v.it_interval.tv_sec = 1;
38 v.it_interval.tv_usec = 0;
39 v.it_value = v.it_interval;
40 setitimer(ITIMER_REAL, &v, NULL);
41 #else
42 /* this is just eye candy: errors are not fatal */
43 progress_event = CreateEvent(NULL, FALSE, FALSE, NULL);
44 if (progress_event) {
45 progress_thread = (HANDLE) _beginthreadex(NULL, 0, heartbeat, NULL, 0, NULL);
46 if (!progress_thread )
47 error("cannot create progress indicator");
48 } else
49 error("cannot allocate resources for progress indicator");
50 #endif
53 static void clear_progress_signal(void)
55 #ifndef __MINGW32__
56 struct itimerval v = {{0,},};
57 setitimer(ITIMER_REAL, &v, NULL);
58 signal(SIGALRM, SIG_IGN);
59 #else
60 /* this is just eye candy: errors are not fatal */
61 if (progress_event)
62 SetEvent(progress_event); /* tells thread to terminate */
63 if (progress_thread) {
64 int rc = WaitForSingleObject(progress_thread, 1000);
65 if (rc == WAIT_TIMEOUT)
66 error("progress thread did not terminate timely");
67 else if (rc != WAIT_OBJECT_0)
68 error("waiting for progress thread failed: %lu",
69 GetLastError());
70 CloseHandle(progress_thread);
72 if (progress_event)
73 CloseHandle(progress_event);
74 progress_event = NULL;
75 progress_thread = NULL;
76 #endif
78 progress_update = 0;
81 int display_progress(struct progress *progress, unsigned n)
83 if (progress->delay) {
84 char buf[80];
85 if (!progress_update || --progress->delay)
86 return 0;
87 if (progress->total) {
88 unsigned percent = n * 100 / progress->total;
89 if (percent > progress->delayed_percent_treshold) {
90 /* inhibit this progress report entirely */
91 clear_progress_signal();
92 progress->delay = -1;
93 progress->total = 0;
94 return 0;
97 if (snprintf(buf, sizeof(buf),
98 progress->delayed_title, progress->total))
99 fprintf(stderr, "%s\n", buf);
101 if (progress->total) {
102 unsigned percent = n * 100 / progress->total;
103 if (percent != progress->last_percent || progress_update) {
104 progress->last_percent = percent;
105 fprintf(stderr, "%s%4u%% (%u/%u) done\r",
106 progress->prefix, percent, n, progress->total);
107 progress_update = 0;
108 progress->need_lf = 1;
109 return 1;
111 } else if (progress_update) {
112 fprintf(stderr, "%s%u\r", progress->prefix, n);
113 progress_update = 0;
114 progress->need_lf = 1;
115 return 1;
117 return 0;
120 void start_progress(struct progress *progress, const char *title,
121 const char *prefix, unsigned total)
123 char buf[80];
124 progress->prefix = prefix;
125 progress->total = total;
126 progress->last_percent = -1;
127 progress->delay = 0;
128 progress->need_lf = 0;
129 if (snprintf(buf, sizeof(buf), title, total))
130 fprintf(stderr, "%s\n", buf);
131 set_progress_signal();
134 void start_progress_delay(struct progress *progress, const char *title,
135 const char *prefix, unsigned total,
136 unsigned percent_treshold, unsigned delay)
138 progress->prefix = prefix;
139 progress->total = total;
140 progress->last_percent = -1;
141 progress->delayed_percent_treshold = percent_treshold;
142 progress->delayed_title = title;
143 progress->delay = delay;
144 progress->need_lf = 0;
145 set_progress_signal();
148 void stop_progress(struct progress *progress)
150 clear_progress_signal();
151 if (progress->need_lf)
152 fputc('\n', stderr);