This is the same module as posted earlier but now rewritten in XS. I've
tested it by putting the test file in the main test suite, since I cannot
test it yet in the sub-project dir, so I won't commit the test till it'll
be possible to run tests in the sub-projects:
--- /dev/null Thu Jan 1 07:30:00 1970
+++ Apache-Scoreboard/apxs/send.c Fri Apr 5 23:53:15 2002
@@ -0,0 +1,62 @@
+#define REMOTE_SCOREBOARD_TYPE "application/x-httpd-scoreboard"
+
+#ifndef Move
+#define Move(s,d,n,t) (void)memmove((char*)(d),(char*)(s), (n) * sizeof(t))
+#endif
+#ifndef Copy
+#define Copy(s,d,n,t) (void)memcpy((char*)(d),(char*)(s), (n) * sizeof(t))
+#endif
+
+#define SIZE16 2
+
+static void pack16(unsigned char *s, int p)
+{
+ short ashort = htons(p);
+ Move(&ashort, s, SIZE16, unsigned char);
+}
+
+static unsigned short unpack16(unsigned char *s)
+{
+ unsigned short ashort;
+ Copy(s, &ashort, SIZE16, char);
+ return ntohs(ashort);
+}
+
+
+#define WRITE_BUFF(buf, size, r) \
+ if (ap_rwrite(buf, size, r) < 0) { return APR_EGENERAL; }
+
+static int scoreboard_send(request_rec *r)
+{
+ int i, psize, ssize, tsize;
+ char buf[SIZE16*2];
+ char *ptr = buf;
+
+ for (i = 0; i < server_limit; i++) {
+ if (!ap_scoreboard_image->parent[i].pid) {
+ break;
+ }
+ }
+
+ psize = i * sizeof(process_score);
+ ssize = i * sizeof(worker_score);
+ tsize = psize + ssize + sizeof(global_score) + sizeof(buf);
+
+ pack16(ptr, psize);
+ ptr += SIZE16;
+ pack16(ptr, ssize);
+
+ ap_set_content_length(r, tsize);
+ r->content_type = REMOTE_SCOREBOARD_TYPE;
+
+ if (!r->header_only) {
+ WRITE_BUFF(&buf[0], sizeof(buf), r);
+ WRITE_BUFF(&ap_scoreboard_image->parent[0], psize, r);
+ WRITE_BUFF(&ap_scoreboard_image->servers[0], ssize, r);
+ WRITE_BUFF(&ap_scoreboard_image->global, sizeof(global_score), r);
+ }
+
+ return APR_SUCCESS;
+}
+
+
--- /dev/null Thu Jan 1 07:30:00 1970
+++ Apache-Scoreboard/Scoreboard.pm Sat Apr 6 02:33:44 2002
@@ -0,0 +1,305 @@
+package Apache::Scoreboard;
+
+use strict;
+use constant DEBUG => 0;
+
+BEGIN {
+ no strict;
+ $VERSION = '0.01';
+ @ISA = qw(DynaLoader);
+ if ($ENV{MOD_PERL}) {
+ __PACKAGE__->bootstrap($VERSION);
+ }
+ else {
+ require Apache::DummyScoreboard;
+ }
+}
+
+my $ua;
+
+sub http_fetch {
+ my($self, $url) = @_;
+
+ require LWP::UserAgent;
+ unless ($ua) {
+ no strict 'vars';
+ $ua = LWP::UserAgent->new;
+ $ua->agent(join '/', __PACKAGE__, $VERSION);
+ }
+
+ my $request = HTTP::Request->new('GET', $url);
+ my $response = $ua->request($request);
+ unless ($response->is_success) {
+ warn "request failed: ", $response->status_line if DEBUG;
+ return undef;
+ }
+
+ my $type = $response->header('Content-type');
+ unless ($type eq Apache::Scoreboard::REMOTE_SCOREBOARD_TYPE) {
+ warn "invalid scoreboard Content-type: $type" if DEBUG;
+ return undef;
+ }
+
+ $response->content;
+}
+
+sub fetch {
+ my($self, $pool, $url) = @_;
+ $self->thaw($pool, $self->http_fetch($url));
+}
+
+sub fetch_store {
+ my($self, $url, $file) = @_;
+ $self->store($self->http_fetch($url), $file);
+}
+
+sub store {
+ my($self, $frozen_image, $file) = @_;
+ open my $fh, ">$file" or die "open $file: $!";
+ print $fh $frozen_image;
+ close $fh;
+}
+
+sub retrieve {
+ my($self, $pool, $file) = @_;
+ open my $fh, $file or die "open $file: $!";
+ local $/;
+ my $data = <$fh>;
+ close $fh;
+ $self->thaw($pool, $data);
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Apache::Scoreboard - Perl interface to the Apache scoreboard structure
+
+=head1 SYNOPSIS
+
+ use Apache::Scoreboard ();
+
+ #inside httpd
+ my $image = Apache::Scoreboard->image;
+
+ #outside httpd
+ my $image = Apache::Scoreboard->fetch("http://localhost/scoreboard");
+
+=head1 DESCRIPTION
+
+Apache keeps track of server activity in a structure known as the
+I<scoreboard>. There is a I<slot> in the scoreboard for each child
+server, containing information such as status, access count, bytes
+served and cpu time. This same information is used by I<mod_status>
+to provide current server statistics in a human readable form.
+
+=head1 METHODS
+
+=over 4
+
+=item image
+
+This method returns an object for accessing the scoreboard structure
+when running inside the server:
+
+ my $image = Apache::Scoreboard->image;
+
+=item fetch
+
+This method fetches the scoreboard structure from a remote server,
+which must contain the following configuration:
+
+ PerlModule Apache::Scoreboard
+ <Location /scoreboard>
+ SetHandler perl-script
+ PerlHandler Apache::Scoreboard::send
+ order deny,allow
+ deny from all
+ #same config you have for mod_status
+ allow from 127.0.0.1 ...
+ </Location>
+
+If the remote server is not configured to use mod_perl or simply for a
+smaller footprint, see the I<apxs> directory for I<mod_scoreboard_send>:
+
+ LoadModule scoreboard_send_module libexec/mod_scoreboard_send.so
+
+ <Location /scoreboard>
+ SetHandler scoreboard-send-handler
+ order deny,allow
+ deny from all
+ allow from 127.0.0.1 ...
+ </Location>
+
+The image can then be fetched via http:
+
+ my $image = Apache::Scoreboard->fetch("http://remote-hostname/scoreboard");
+
+=item fetch_store
+
+=item retrieve
+
+The I<fetch_store> method is used to fetch the image once from and
+remote server and save it to disk. The image can then be read by
+other processes with the I<retrieve> function.
+This way, multiple processes can access a remote scoreboard with just
+a single request to the remote server. Example:
+
+ Apache::Scoreboard->fetch_store($url, $local_filename);
+
+ my $image = Apache::Scoreboard->retrieve($local_filename);
+
+=item parent
+
+This method returns a reference to the first parent score entry in the
+list, blessed into the I<Apache::ParentScore> class:
+
+ my $parent = $image->parent;
+
+Iterating over the list of scoreboard slots is done like so:
+
+ for (my $parent = $image->parent; $parent; $parent = $parent->next) {
+ my $pid = $parent->pid; #pid of the child
+
+ my $server = $parent->server; #Apache::ServerScore object
+
+ ...
+ }
+
+=item pids
+
+Returns an array reference of all child pids:
+
+ my $pids = $image->pids;
+
+=back
+
+=head2 The Apache::ParentScore Class
+
+=over 4
+
+=item pid
+
+The parent keeps track of child pids with this field:
+
+ my $pid = $parent->pid;
+
+=item server
+
+Returns a reference to the corresponding I<Apache::ServerScore>
+structure:
+
+ my $server = $parent->server;
+
+=item next
+
+Returns a reference to the next I<Apache::ParentScore> object in the list:
+
+ my $p = $parent->next;
+
+=back
+
+=head2 The Apache::ServerScore Class
+
+=over 4
+
+=item status
+
+This method returns the status of child server, which is one of:
+
+ "_" Waiting for Connection
+ "S" Starting up
+ "R" Reading Request
+ "W" Sending Reply
+ "K" Keepalive (read)
+ "D" DNS Lookup
+ "L" Logging
+ "G" Gracefully finishing
+ "." Open slot with no current process
+
+=item access_count
+
+The access count of the child server:
+
+ my $count = $server->access_count;
+
+=item request
+
+The first 64 characters of the HTTP request:
+
+ #e.g.: GET /scoreboard HTTP/1.0
+ my $request = $server->request;
+
+=item client
+
+The ip address or hostname of the client:
+
+ #e.g.: 127.0.0.1
+ my $client = $server->client;
+
+=item bytes_served
+
+Total number of bytes served by this child:
+
+ my $bytes = $server->bytes_served;
+
+=item conn_bytes
+
+Number of bytes served by the last connection in this child:
+
+ my $bytes = $server->conn_bytes;
+
+=item conn_count
+
+Number of requests served by the last connection in this child:
+
+ my $count = $server->conn_count;
+
+=item times
+
+In a list context, returns a four-element list giving the user and
+system times, in seconds, for this process and the children of this
+process.
+
+ my($user, $system, $cuser, $csystem) = $server->times;
+
+In a scalar context, returns the overall CPU percentage for this server:
+
+ my $cpu = $server->times;
+
+=item start_time
+
+In a list context this method returns a 2 element list with the seconds and
+microseconds since the epoch, when the request was started. In scalar
+context it returns floating seconds like Time::HiRes::time()
+
+ my($tv_sec, $tv_usec) = $server->start_time;
+
+ my $secs = $server->start_time;
+
+=item stop_time
+
+In a list context this method returns a 2 element list with the seconds and
+microseconds since the epoch, when the request was finished. In scalar
+context it returns floating seconds like Time::HiRes::time()
+
+ my($tv_sec, $tv_usec) = $server->stop_time;
+
+ my $secs = $server->stop_time;
+
+=item req_time
+
+Returns the time taken to process the request in microseconds:
+
+ my $req_time = $server->req_time;
+
+=back
+
+=head1 SEE ALSO
+
+Apache::VMonitor(3), GTop(3)
+
+=head1 AUTHOR
+
+Doug MacEachern
--- /dev/null Thu Jan 1 07:30:00 1970
+++ Apache-Scoreboard/Scoreboard.xs Sat Apr 6 20:53:29 2002
@@ -0,0 +1,617 @@
+#define PERL_NO_GET_CONTEXT /* we want efficiency */
+/* #include "xs/modperl_xs_typedefs.h" */
+#include "mod_perl.h"
+#include "modperl_xs_sv_convert.h"
+#include "modperl_xs_typedefs.h"
+
+#include "scoreboard.h"
+
+/* scoreboard */
+typedef struct {
+ scoreboard *sb;
+ apr_pool_t *pool;
+} modperl_scoreboard_t;
+
+typedef struct {
+ worker_score record;
+ int parent_idx;
+ int worker_idx;
+} modperl_worker_score_t;
+
+typedef struct {
+ process_score record;
+ int idx;
+ scoreboard *sb;
+ apr_pool_t *pool;
+} modperl_parent_score_t;
+
+typedef modperl_scoreboard_t *Apache__Scoreboard;
+typedef modperl_worker_score_t *Apache__ScoreboardWorkerScore;
+typedef modperl_parent_score_t *Apache__ScoreboardParentScore;
+
+/* XXX: When documenting don't forget to add the new 'vhost' accessor */
+/* and port accessor if it gets added (need to add it here too) */
+
+int server_limit, thread_limit;
+
+static char status_flags[SERVER_NUM_STATUS];
+
+#define scoreboard_up_time(image) \
+ (apr_uint32_t)((apr_time_now() - image->sb->global->restart_time) /
+APR_USEC_PER_SEC);
+
+#define parent_score_pid(mps) mps->record.pid
+
+#define worker_score_most_recent(mws) \
+ (apr_uint32_t)((apr_time_now() - mws->record.last_used) / APR_USEC_PER_SEC);
+
+#define worker_score_access_count(mws) mws->record.access_count
+#define worker_score_bytes_served(mws) mws->record.bytes_served
+#define worker_score_my_access_count(mws) mws->record.my_access_count
+#define worker_score_my_bytes_served(mws) mws->record.my_bytes_served
+#define worker_score_conn_bytes(mws) mws->record.conn_bytes
+#define worker_score_conn_count(mws) mws->record.conn_count
+#define worker_score_client(mws) mws->record.client
+#define worker_score_request(mws) mws->record.request
+#define worker_score_vhost(mws) mws->record.vhost
+
+/* a worker that have served/serves at least one request and isn't
+ * dead yet */
+#define LIVE_WORKER(ws) ws.access_count != 0 || \
+ ws.status != SERVER_DEAD
+
+/* a worker that does something at this very moment */
+#define ACTIVE_WORKER(ws) ws.access_count != 0 || \
+ (ws.status != SERVER_DEAD && ws.status != SERVER_READY)
+
+
+
+
+
+static void status_flags_init(void)
+{
+ status_flags[SERVER_DEAD] = '.';
+ status_flags[SERVER_READY] = '_';
+ status_flags[SERVER_STARTING] = 'S';
+ status_flags[SERVER_BUSY_READ] = 'R';
+ status_flags[SERVER_BUSY_WRITE] = 'W';
+ status_flags[SERVER_BUSY_KEEPALIVE] = 'K';
+ status_flags[SERVER_BUSY_LOG] = 'L';
+ status_flags[SERVER_BUSY_DNS] = 'D';
+ status_flags[SERVER_CLOSING] = 'C';
+ status_flags[SERVER_GRACEFUL] = 'G';
+ status_flags[SERVER_IDLE_KILL] = 'I';
+}
+
+#include "apxs/send.c"
+
+MODULE = Apache::Scoreboard PACKAGE = Apache::Scoreboard PREFIX = scoreboard_
+
+BOOT:
+{
+ HV *stash;
+
+ /* XXX: this must be performed only once and before other threads are spawned.
+ * but not sure. could be that need to use local storage.
+ *
+ */
+ status_flags_init();
+
+ ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
+ ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
+
+ stash = gv_stashpv("Apache::Const", TRUE);
+ newCONSTSUB(stash, "SERVER_LIMIT", newSViv(server_limit));
+
+ stash = gv_stashpv("Apache::Const", TRUE);
+ newCONSTSUB(stash, "THREAD_LIMIT", newSViv(thread_limit));
+
+ stash = gv_stashpv("Apache::Scoreboard", TRUE);
+ newCONSTSUB(stash, "REMOTE_SCOREBOARD_TYPE",
+ newSVpv(REMOTE_SCOREBOARD_TYPE, 0));
+}
+
+int
+scoreboard_send(r)
+ Apache::RequestRec r
+
+
+
+SV *
+freeze(image)
+ Apache::Scoreboard image
+
+ PREINIT:
+ int i, psize, ssize, tsize;
+ char buf[SIZE16*2];
+ char *dptr, *data, *ptr = buf;
+ scoreboard *sb;
+
+ CODE:
+ sb = image->sb;
+
+ for (i = 0; i < server_limit; i++) {
+ if (!sb->parent[i].pid) {
+ break;
+ }
+ }
+
+ psize = i * sizeof(process_score);
+ ssize = i * sizeof(worker_score);
+ tsize = psize + ssize + sizeof(global_score) + sizeof(buf);
+ /* fprintf(stderr, "sizes %d, %d, %d, %d, %d, %d\n",
+ i, psize, ssize, sizeof(global_score) , sizeof(buf), tsize); */
+
+ data = (char *)apr_palloc(image->pool, tsize);
+
+ pack16(ptr, psize);
+ ptr += SIZE16;
+ pack16(ptr, ssize);
+
+ /* fill the data buffer with the data we want to freeze */
+ dptr = data;
+ Move(buf, dptr, sizeof(buf), char);
+ dptr += sizeof(buf);
+ Move(&sb->parent[0], dptr, psize, char);
+ dptr += psize;
+ Move(&sb->servers[0], dptr, ssize, char);
+ dptr += ssize;
+ Move(&sb->global, dptr, sizeof(global_score), char);
+
+ /* an equivalent C function can return 'data', in case of XS it'll
+ * try to convert char *data to PV, using strlen(), which will
+ * lose data, since it won't continue past the first \0
+ * char. Therefore in this case we explicitly return SV* and using
+ * newSVpvn(data, tsize) to tell the exact size */
+ RETVAL = newSVpvn(data, tsize);
+
+ OUTPUT:
+ RETVAL
+
+Apache::Scoreboard
+thaw(CLASS, pool, packet)
+ SV *CLASS
+ APR::Pool pool
+ SV *packet
+
+ PREINIT:
+ modperl_scoreboard_t *image;
+ scoreboard *sb;
+ int psize, ssize;
+ char *ptr;
+
+ CODE:
+ if (!(SvOK(packet) && SvCUR(packet) > (SIZE16*2))) {
+ XSRETURN_UNDEF;
+ }
+
+ CLASS = CLASS; /* avoid warnings */
+
+ image = (modperl_scoreboard_t *)apr_palloc(pool, sizeof(*image));
+ sb = (scoreboard *)apr_palloc(pool, sizeof(scoreboard));
+ sb->parent = (process_score *)apr_palloc(pool, sizeof(process_score *));
+ sb->servers = (worker_score **)apr_palloc(pool, server_limit *
+sizeof(worker_score));
+ sb->global = (global_score *)apr_palloc(pool, sizeof(global_score *));
+
+ ptr = SvPVX(packet);
+ psize = unpack16(ptr);
+ ptr += SIZE16;
+ ssize = unpack16(ptr);
+ ptr += SIZE16;
+
+ Move(ptr, &sb->parent[0], psize, char);
+ ptr += psize;
+ Move(ptr, &sb->servers[0], ssize, char);
+ ptr += ssize;
+ Move(ptr, &sb->global, sizeof(global_score), char);
+
+ image->pool = pool;
+ image->sb = sb;
+
+ RETVAL = image;
+
+ OUTPUT:
+ RETVAL
+
+Apache::Scoreboard
+image(CLASS, pool)
+ SV *CLASS
+ APR::Pool pool
+
+ CODE:
+ RETVAL = (modperl_scoreboard_t *)apr_palloc(pool, sizeof(*RETVAL));
+
+ if (ap_exists_scoreboard_image()) {
+ RETVAL->sb = ap_scoreboard_image;
+ RETVAL->pool = pool;
+ }
+ else {
+ Perl_croak(aTHX_ "ap_scoreboard_image doesn't exist");
+ }
+
+ CLASS = CLASS; /* avoid warnings */
+
+ OUTPUT:
+ RETVAL
+
+Apache::ScoreboardParentScore
+parent_score(self, idx=0)
+ Apache::Scoreboard self
+ int idx
+
+ CODE:
+ if (self->sb->parent[idx].pid) {
+ RETVAL = (modperl_parent_score_t *)apr_pcalloc(self->pool, (sizeof(*RETVAL)));
+ RETVAL->record = self->sb->parent[idx];
+ RETVAL->idx = idx;
+ RETVAL->sb = self->sb;
+ RETVAL->pool = self->pool;
+ }
+ else {
+ XSRETURN_UNDEF;
+ }
+
+ OUTPUT:
+ RETVAL
+
+Apache::ScoreboardWorkerScore
+worker_score(self, parent_idx, worker_idx)
+ Apache::Scoreboard self
+ int parent_idx
+ int worker_idx
+
+ CODE:
+ RETVAL = (modperl_worker_score_t *)apr_pcalloc(self->pool, (sizeof(*RETVAL)));
+
+ RETVAL->record = self->sb->servers[parent_idx][worker_idx];
+ RETVAL->parent_idx = parent_idx;
+ RETVAL->worker_idx = worker_idx;
+
+ OUTPUT:
+ RETVAL
+
+SV *
+pids(self)
+ Apache::Scoreboard self
+
+ PREINIT:
+ AV *av = newAV();
+ int i;
+ scoreboard *sb;
+
+ CODE:
+ sb = self->sb;
+ for (i = 0; i < server_limit; i++) {
+ if (!(sb->parent[i].pid)) {
+ break;
+ }
+ /* fprintf(stderr, "pids: server %d: pid %d\n",
+ i, (int)(sb->parent[i].pid)); */
+ av_push(av, newSViv(sb->parent[i].pid));
+ }
+
+ RETVAL = newRV_noinc((SV*)av);
+
+ OUTPUT:
+ RETVAL
+
+# XXX: need to move pid_t => apr_proc_t and work with pid->pid as in
+# find_child_by_pid from scoreboard.c
+
+int
+parent_idx_by_pid(self, pid)
+ Apache::Scoreboard self
+ pid_t pid
+
+ PREINIT:
+ int i;
+ scoreboard *sb;
+
+ CODE:
+ sb = self->sb;
+ RETVAL = -1;
+
+ for (i = 0; i < server_limit; i++) {
+ if (sb->parent[i].pid == pid) {
+ RETVAL = i;
+ break;
+ }
+ }
+
+ OUTPUT:
+ RETVAL
+
+SV *
+thread_numbers(self, parent_idx)
+ Apache::Scoreboard self
+ int parent_idx
+
+ PREINIT:
+ AV *av = newAV();
+ int i;
+ scoreboard *sb;
+
+ CODE:
+ sb = self->sb;
+
+ for (i = 0; i < thread_limit; ++i) {
+ /* fprintf(stderr, "thread_num: server %d, thread %d pid %d\n",
+ i, sb->servers[parent_idx][i].thread_num,
+ (int)(sb->parent[parent_idx].pid)); */
+
+ av_push(av, newSViv(sb->servers[parent_idx][i].thread_num));
+ }
+
+ RETVAL = newRV_noinc((SV*)av);
+
+ OUTPUT:
+ RETVAL
+
+apr_uint32_t
+scoreboard_up_time(self)
+ Apache::Scoreboard self
+
+MODULE = Apache::Scoreboard PACKAGE = Apache::ScoreboardParentScore PREFIX =
+parent_score_
+
+Apache::ScoreboardParentScore
+next(self)
+ Apache::ScoreboardParentScore self
+
+ PREINIT:
+ int next_idx;
+
+ CODE:
+ next_idx = self->idx + 1;
+
+ if (self->sb->parent[next_idx].pid) {
+ RETVAL = (modperl_parent_score_t *)apr_pcalloc(self->pool, sizeof(*RETVAL));
+ RETVAL->record = self->sb->parent[next_idx];
+ RETVAL->idx = next_idx;
+ RETVAL->sb = self->sb;
+ RETVAL->pool = self->pool;
+ }
+ else {
+ XSRETURN_UNDEF;
+ }
+
+ OUTPUT:
+ RETVAL
+
+Apache::ScoreboardWorkerScore
+worker_score(self)
+ Apache::ScoreboardParentScore self
+
+ CODE:
+ RETVAL = (modperl_worker_score_t *)apr_pcalloc(self->pool, sizeof(*RETVAL));
+ RETVAL->record = self->sb->servers[self->idx][0];
+ RETVAL->parent_idx = self->idx;
+ RETVAL->worker_idx = 0;
+
+ OUTPUT:
+ RETVAL
+
+Apache::ScoreboardWorkerScore
+next_worker_score(self, mws)
+ Apache::ScoreboardParentScore self
+ Apache::ScoreboardWorkerScore mws
+
+ PREINIT:
+ int next_idx;
+
+ CODE:
+ next_idx = mws->worker_idx + 1;
+ if (next_idx < thread_limit) {
+ RETVAL = (modperl_worker_score_t *)apr_pcalloc(self->pool, sizeof(*RETVAL));
+ RETVAL->record = self->sb->servers[mws->parent_idx][next_idx];
+ RETVAL->parent_idx = mws->parent_idx;
+ RETVAL->worker_idx = next_idx;
+ }
+ else {
+ XSRETURN_UNDEF;
+ }
+
+ OUTPUT:
+ RETVAL
+
+
+Apache::ScoreboardWorkerScore
+next_live_worker_score(self, mws)
+ Apache::ScoreboardParentScore self
+ Apache::ScoreboardWorkerScore mws
+
+ PREINIT:
+ int next_idx;
+ int found = 0;
+
+ CODE:
+ next_idx = mws->worker_idx;
+
+ while (++next_idx < thread_limit) {
+ if (LIVE_WORKER(self->sb->servers[mws->parent_idx][next_idx])) {
+ RETVAL = (modperl_worker_score_t *)apr_pcalloc(self->pool,
+sizeof(*RETVAL));
+ RETVAL->record = self->sb->servers[mws->parent_idx][next_idx];
+ RETVAL->parent_idx = mws->parent_idx;
+ RETVAL->worker_idx = next_idx;
+ found++;
+ break;
+ }
+ }
+
+ if (!found) {
+ XSRETURN_UNDEF;
+ }
+
+ OUTPUT:
+ RETVAL
+
+
+
+Apache::ScoreboardWorkerScore
+next_active_worker_score(self, mws)
+ Apache::ScoreboardParentScore self
+ Apache::ScoreboardWorkerScore mws
+
+ PREINIT:
+ int next_idx;
+ int found = 0;
+
+ CODE:
+ next_idx = mws->worker_idx;
+ while (++next_idx < thread_limit) {
+ if (ACTIVE_WORKER(self->sb->servers[mws->parent_idx][next_idx])) {
+ RETVAL = (modperl_worker_score_t *)apr_pcalloc(self->pool,
+sizeof(*RETVAL));
+ RETVAL->record = self->sb->servers[mws->parent_idx][next_idx];
+ RETVAL->parent_idx = mws->parent_idx;
+ RETVAL->worker_idx = next_idx;
+ found++;
+ break;
+ }
+ }
+
+ if (!found) {
+ XSRETURN_UNDEF;
+ }
+
+ OUTPUT:
+ RETVAL
+
+pid_t
+parent_score_pid(self)
+ Apache::ScoreboardParentScore self
+
+MODULE = Apache::Scoreboard PACKAGE = Apache::ScoreboardWorkerScore PREFIX =
+worker_score_
+
+void
+times(self)
+ Apache::ScoreboardWorkerScore self
+
+ PPCODE:
+ if (GIMME == G_ARRAY) {
+ /* same return values as CORE::times() */
+ EXTEND(sp, 4);
+ PUSHs(sv_2mortal(newSViv(self->record.times.tms_utime)));
+ PUSHs(sv_2mortal(newSViv(self->record.times.tms_stime)));
+ PUSHs(sv_2mortal(newSViv(self->record.times.tms_cutime)));
+ PUSHs(sv_2mortal(newSViv(self->record.times.tms_cstime)));
+ }
+ else {
+#ifdef _SC_CLK_TCK
+ float tick = sysconf(_SC_CLK_TCK);
+#else
+ float tick = HZ;
+#endif
+ if (self->record.access_count) {
+ /* cpu %, same value mod_status displays */
+ float RETVAL = (self->record.times.tms_utime +
+ self->record.times.tms_stime +
+ self->record.times.tms_cutime +
+ self->record.times.tms_cstime);
+ XPUSHs(sv_2mortal(newSVnv((double)RETVAL/tick)));
+ }
+ else {
+
+ XPUSHs(sv_2mortal(newSViv((0))));
+ }
+ }
+
+
+void
+start_time(self)
+ Apache::ScoreboardWorkerScore self
+
+ ALIAS:
+ stop_time = 1
+
+ PREINIT:
+ apr_time_t tp;
+
+ PPCODE:
+ ix = ix; /* warnings */
+ tp = (XSANY.any_i32 == 0) ?
+ self->record.start_time : self->record.stop_time;
+
+ /* fprintf(stderr, "start_time: %5" APR_TIME_T_FMT "\n", tp); */
+
+ /* do the same as Time::HiRes::gettimeofday */
+ if (GIMME == G_ARRAY) {
+ EXTEND(sp, 2);
+ PUSHs(sv_2mortal(newSViv(tp / APR_USEC_PER_SEC)));
+ PUSHs(sv_2mortal(newSViv(tp / APR_USEC_PER_SEC - tp % APR_USEC_PER_SEC )));
+ }
+ else {
+ EXTEND(sp, 1);
+ PUSHs(sv_2mortal(newSVnv((double)tp / APR_USEC_PER_SEC )));
+ }
+
+long
+req_time(self)
+ Apache::ScoreboardWorkerScore self
+
+ CODE:
+ if (self->record.start_time == 0L) {
+ RETVAL = 0L;
+ }
+ else {
+ RETVAL = (long)
+ ((self->record.stop_time - self->record.start_time) / 1000);
+ }
+ if (RETVAL < 0L || !self->record.access_count) {
+ RETVAL = 0L;
+ }
+
+ OUTPUT:
+ RETVAL
+
+SV *
+worker_score_status(self)
+ Apache::ScoreboardWorkerScore self
+
+ CODE:
+ RETVAL = newSV(0);
+ sv_setnv(RETVAL, (double)self->record.status);
+ sv_setpvf(RETVAL, "%c", status_flags[self->record.status]);
+ SvNOK_on(RETVAL); /* dual-var */
+
+ OUTPUT:
+ RETVAL
+
+
+
+unsigned long
+worker_score_access_count(self)
+ Apache::ScoreboardWorkerScore self
+
+unsigned long
+worker_score_bytes_served(self)
+ Apache::ScoreboardWorkerScore self
+
+unsigned long
+worker_score_my_access_count(self)
+ Apache::ScoreboardWorkerScore self
+
+unsigned long
+worker_score_my_bytes_served(self)
+ Apache::ScoreboardWorkerScore self
+
+unsigned long
+worker_score_conn_bytes(self)
+ Apache::ScoreboardWorkerScore self
+
+unsigned short
+worker_score_conn_count(self)
+ Apache::ScoreboardWorkerScore self
+
+char *
+worker_score_client(self)
+ Apache::ScoreboardWorkerScore self
+
+char *
+worker_score_request(self)
+ Apache::ScoreboardWorkerScore self
+
+char *
+worker_score_vhost(self)
+ Apache::ScoreboardWorkerScore self
+
+apr_uint32_t
+worker_score_most_recent(self)
+ Apache::ScoreboardWorkerScore self
--- /dev/null Thu Jan 1 07:30:00 1970
+++ Apache-Scoreboard/Makefile.PL Sat Apr 6 21:42:43 2002
@@ -0,0 +1,95 @@
+#use strict;
+#use warnings FATAL => 'all';
+
+use lib qw(lib ../lib ../Apache-Test/lib);
+use ModPerl::MM qw(test clean);
+
+*MY::test = \&Apache::TestMM::test;
+*MY::clean = \&Apache::TestMM::clean;
+
+use constant HAS_APACHE_TEST => eval {require Apache::Test};
+
+# enable 'make test|clean'
+#use Apache::TestMM qw(test clean);
+
+# enable 'make test|clean'
+#if (HAS_APACHE_TEST) {
+# require Apache::TestMM;
+# Apache::TestMM->import(qw(test clean));
+#} else {
+# warn "consider installing Apache::Test\n";
+#}
+
+# prerequisites
+my %require =
+ (
+ "Apache::Test" => "", # any version will do?
+ );
+
+my @scripts = ();
+
+if (HAS_APACHE_TEST) {
+ # accept the configs from command line
+ Apache::TestMM::filter_args();
+ Apache::TestMM::generate_script('t/TEST');
+ push @scripts, 't/TEST';
+}
+
+ModPerl::MM::WriteMakefile(
+ NAME => 'Apache::Scoreboard',
+ VERSION_FROM => 'Scoreboard.pm',
+ PREREQ_PM => \%require,
+ clean => {
+ FILES => "@{ clean_files() }",
+ },
+);
+
+sub clean_files {
+ return [@scripts];
+}
+
+
+__END__
+
+use ExtUtils::MakeMaker;
+
+use strict;
+use Apache::src ();
+
+my $src = Apache::src->new;
+
+WriteMakefile(
+ 'NAME' => 'Apache::Scoreboard',
+ 'VERSION_FROM' => 'Scoreboard.pm',
+ 'INC' => $src->inc,
+ 'DEFINE' => $src->define,
+ 'TYPEMAPS' => $src->typemaps,
+ 'dist' => {
+ #PREOP => 'pod2text Scoreboard.pm > README',
+ },
+ 'macro' => {
+ CVSROOT => 'modperl.com:/local/cvs_repository',
+ },
+);
+
+sub MY::postamble {
+ return <<'EOF';
+
+cvs_tag :
+ cvs -d $(CVSROOT) tag v$(VERSION_SYM) .
+ @echo update Scoreboard.pm VERSION now
+EOF
+}
+
+sub MY::top_targets {
+ my $self = shift;
+ my $string = $self->MM::top_targets;
+
+ $string .= <<'EOF';
+dummy:
+ cd Dummy && $(PERL) Makefile.PL -g
+
+EOF
+
+ $string;
+}
--- /dev/null Thu Jan 1 07:30:00 1970
+++ Apache-Scoreboard/typemap Sat Apr 6 02:00:04 2002
@@ -0,0 +1,9 @@
+Apache::RequestRec T_APACHEOBJ
+APR::Pool T_PTROBJ
+Apache::Scoreboard T_PTROBJ
+Apache::ScoreboardWorkerScore T_PTROBJ
+Apache::ScoreboardParentScore T_PTROBJ
+pid_t T_IV
+apr_uint32_t T_IV
+#float T_FLOAT
+
__________________________________________________________________
Stas Bekman JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/ mod_perl Guide ---> http://perl.apache.org
mailto:[EMAIL PROTECTED] http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org http://ticketmaster.com
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]